Files
drone-detector/server/tests/middleware/ip-restriction.test.js
2025-09-15 06:35:20 +02:00

288 lines
7.9 KiB
JavaScript

const { describe, it, beforeEach, afterEach, before, after } = require('mocha');
const { expect } = require('chai');
const sinon = require('sinon');
const IPRestrictionMiddleware = require('../../middleware/ip-restriction');
const { setupTestEnvironment, teardownTestEnvironment, cleanDatabase, mockRequest, mockResponse, mockNext, createTestUser, createTestTenant } = require('../setup');
describe('IP Restriction Middleware', () => {
let models, sequelize, ipRestriction;
before(async () => {
({ models, sequelize } = await setupTestEnvironment());
ipRestriction = new IPRestrictionMiddleware();
});
after(async () => {
await teardownTestEnvironment();
});
beforeEach(async () => {
await cleanDatabase();
});
describe('checkIPRestriction', () => {
it('should allow access when IP restrictions disabled', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: false,
allowed_ips: '192.168.1.1,10.0.0.1'
});
const req = mockRequest({
ip: '127.0.0.1',
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(next.errors).to.have.length(0);
});
it('should allow access from allowed IP', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: '192.168.1.1,10.0.0.1,127.0.0.1'
});
const req = mockRequest({
ip: '192.168.1.1',
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(next.errors).to.have.length(0);
});
it('should block access from non-allowed IP', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: '192.168.1.1,10.0.0.1'
});
const req = mockRequest({
ip: '192.168.2.1',
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(res.statusCode).to.equal(403);
expect(res.data).to.deep.equal({
success: false,
message: 'Access denied: IP address not allowed',
ip: '192.168.2.1'
});
});
it('should allow access when tenant not found', async () => {
const req = mockRequest({
ip: '192.168.1.1',
tenant: 'nonexistent-tenant'
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(next.errors).to.have.length(0);
});
it('should extract IP from x-forwarded-for header', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: '203.0.113.1'
});
const req = mockRequest({
ip: '127.0.0.1', // Local proxy IP
headers: { 'x-forwarded-for': '203.0.113.1, 198.51.100.1' },
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(next.errors).to.have.length(0);
});
it('should extract IP from x-real-ip header', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: '203.0.113.2'
});
const req = mockRequest({
ip: '127.0.0.1',
headers: { 'x-real-ip': '203.0.113.2' },
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(next.errors).to.have.length(0);
});
it('should handle CIDR notation in allowed IPs', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: '192.168.1.0/24,10.0.0.0/8'
});
const req = mockRequest({
ip: '192.168.1.100',
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(next.errors).to.have.length(0);
});
it('should block IP outside CIDR range', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: '192.168.1.0/24'
});
const req = mockRequest({
ip: '192.168.2.1',
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(res.statusCode).to.equal(403);
});
it('should allow access from Docker container networks', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: '192.168.1.1'
});
const dockerIPs = ['172.17.0.1', '172.18.0.1', '172.19.0.1'];
for (const ip of dockerIPs) {
const req = mockRequest({
ip: ip,
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(next.errors).to.have.length(0);
}
});
it('should allow management routes regardless of IP restrictions', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: '192.168.1.1'
});
const managementPaths = [
'/api/management/status',
'/api/management/health',
'/api/management/system-info'
];
for (const path of managementPaths) {
const req = mockRequest({
ip: '192.168.2.1', // Not in allowed IPs
path: path,
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(next.errors).to.have.length(0);
}
});
it('should handle empty allowed_ips list', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: ''
});
const req = mockRequest({
ip: '192.168.1.1',
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(res.statusCode).to.equal(403);
});
it('should handle null allowed_ips', async () => {
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: null
});
const req = mockRequest({
ip: '192.168.1.1',
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(res.statusCode).to.equal(403);
});
it('should log IP restriction events', async () => {
const consoleLogSpy = sinon.spy(console, 'log');
const tenant = await createTestTenant({
slug: 'test-tenant',
ip_restrictions_enabled: true,
allowed_ips: '192.168.1.1'
});
const req = mockRequest({
ip: '192.168.2.1',
tenant: tenant.slug
});
const res = mockResponse();
const next = mockNext();
await ipRestriction.checkIPRestriction(req, res, next);
expect(consoleLogSpy.calledWith(sinon.match(/🚫.*IP restriction/))).to.be.true;
consoleLogSpy.restore();
});
});
});