feat: support CIDR IP ranges in allowlist (#14243)

This commit is contained in:
Joshua Peek 2024-01-14 20:35:34 -08:00 committed by GitHub
parent 6780b96b23
commit ed8e195ba6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 3 deletions

View File

@ -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();
}
}

View File

@ -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);