feat: support CIDR IP ranges in allowlist (#14243)
This commit is contained in:
parent
6780b96b23
commit
ed8e195ba6
|
|
@ -8,6 +8,27 @@ const reject = (ctx) => {
|
|||
throw Error('Authentication failed. Access denied.');
|
||||
};
|
||||
|
||||
const ipv4Pattern = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
const cidrPattern = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/(\d{1,2})/;
|
||||
|
||||
const ipInCidr = (cidr, ip) => {
|
||||
const cidrMatch = cidr.match(cidrPattern);
|
||||
const ipMatch = ip.match(ipv4Pattern);
|
||||
if (!cidrMatch || !ipMatch) {
|
||||
return false;
|
||||
}
|
||||
const subnetMask = parseInt(cidrMatch[2]);
|
||||
const cidrIpBits = ipv4ToBitsring(cidrMatch[1]).substring(0, subnetMask);
|
||||
const ipBits = ipv4ToBitsring(ip).substring(0, subnetMask);
|
||||
return cidrIpBits === ipBits;
|
||||
};
|
||||
|
||||
const ipv4ToBitsring = (ip) =>
|
||||
ip
|
||||
.split('.')
|
||||
.map((part) => ('00000000' + parseInt(part).toString(2)).slice(-8))
|
||||
.join('');
|
||||
|
||||
module.exports = async (ctx, next) => {
|
||||
const ip = ctx.ips[0] || ctx.ip;
|
||||
const requestPath = ctx.request.path;
|
||||
|
|
@ -39,13 +60,13 @@ module.exports = async (ctx, next) => {
|
|||
}
|
||||
|
||||
if (config.allowlist) {
|
||||
if (config.allowlist.find((item) => ip.includes(item) || requestPath.includes(item) || requestUA.includes(item))) {
|
||||
if (config.allowlist.find((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) {
|
||||
return grant();
|
||||
}
|
||||
}
|
||||
|
||||
if (config.denylist) {
|
||||
if (!config.denylist.find((item) => ip.includes(item) || requestPath.includes(item) || requestUA.includes(item))) {
|
||||
if (!config.denylist.find((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) {
|
||||
return grant();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ describe('access-control', () => {
|
|||
it(`allowlist`, async () => {
|
||||
const key = '1L0veRSSHub';
|
||||
const code = md5('/test/2' + key);
|
||||
process.env.ALLOWLIST = 'est/1,233.233.233.,white';
|
||||
process.env.ALLOWLIST = 'est/1,233.233.233.,103.31.4.0/22,white';
|
||||
process.env.ACCESS_KEY = key;
|
||||
server = require('../../lib/index');
|
||||
const request = supertest(server);
|
||||
|
|
@ -94,6 +94,15 @@ describe('access-control', () => {
|
|||
const response22 = await request.get('/test/2').set('X-Forwarded-For', '233.233.233.233');
|
||||
expect(response22.status).toBe(200);
|
||||
|
||||
const response221 = await request.get('/test/2').set('X-Forwarded-For', '103.31.4.0');
|
||||
expect(response221.status).toBe(200);
|
||||
|
||||
const response222 = await request.get('/test/2').set('X-Forwarded-For', '103.31.7.255');
|
||||
expect(response222.status).toBe(200);
|
||||
|
||||
const response223 = await request.get('/test/2').set('X-Forwarded-For', '103.31.8.0');
|
||||
checkBlock(response223);
|
||||
|
||||
const response23 = await request.get('/test/2').set('user-agent', 'whiteua');
|
||||
expect(response23.status).toBe(200);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue