118 lines
5.5 KiB
TypeScript
118 lines
5.5 KiB
TypeScript
|
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||
|
import { IpMatcher } from '../../../ts/core/routing/matchers/ip.js';
|
||
|
|
||
|
tap.test('IpMatcher - exact match', async () => {
|
||
|
expect(IpMatcher.match('192.168.1.1', '192.168.1.1')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.1', '192.168.1.2')).toEqual(false);
|
||
|
expect(IpMatcher.match('10.0.0.1', '10.0.0.1')).toEqual(true);
|
||
|
});
|
||
|
|
||
|
tap.test('IpMatcher - CIDR notation', async () => {
|
||
|
// /24 subnet
|
||
|
expect(IpMatcher.match('192.168.1.0/24', '192.168.1.1')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.0/24', '192.168.1.255')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.0/24', '192.168.2.1')).toEqual(false);
|
||
|
|
||
|
// /16 subnet
|
||
|
expect(IpMatcher.match('10.0.0.0/16', '10.0.1.1')).toEqual(true);
|
||
|
expect(IpMatcher.match('10.0.0.0/16', '10.0.255.255')).toEqual(true);
|
||
|
expect(IpMatcher.match('10.0.0.0/16', '10.1.0.1')).toEqual(false);
|
||
|
|
||
|
// /32 (single host)
|
||
|
expect(IpMatcher.match('192.168.1.1/32', '192.168.1.1')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.1/32', '192.168.1.2')).toEqual(false);
|
||
|
});
|
||
|
|
||
|
tap.test('IpMatcher - wildcard matching', async () => {
|
||
|
expect(IpMatcher.match('192.168.1.*', '192.168.1.1')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.*', '192.168.1.255')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.*', '192.168.2.1')).toEqual(false);
|
||
|
|
||
|
expect(IpMatcher.match('192.168.*.*', '192.168.0.1')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.*.*', '192.168.255.255')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.*.*', '192.169.0.1')).toEqual(false);
|
||
|
|
||
|
expect(IpMatcher.match('*.*.*.*', '1.2.3.4')).toEqual(true);
|
||
|
expect(IpMatcher.match('*.*.*.*', '255.255.255.255')).toEqual(true);
|
||
|
});
|
||
|
|
||
|
tap.test('IpMatcher - range matching', async () => {
|
||
|
expect(IpMatcher.match('192.168.1.1-192.168.1.10', '192.168.1.1')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.1-192.168.1.10', '192.168.1.5')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.1-192.168.1.10', '192.168.1.10')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.1-192.168.1.10', '192.168.1.11')).toEqual(false);
|
||
|
expect(IpMatcher.match('192.168.1.1-192.168.1.10', '192.168.1.0')).toEqual(false);
|
||
|
});
|
||
|
|
||
|
tap.test('IpMatcher - IPv6-mapped IPv4', async () => {
|
||
|
expect(IpMatcher.match('192.168.1.1', '::ffff:192.168.1.1')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.0/24', '::ffff:192.168.1.100')).toEqual(true);
|
||
|
expect(IpMatcher.match('192.168.1.*', '::FFFF:192.168.1.50')).toEqual(true);
|
||
|
});
|
||
|
|
||
|
tap.test('IpMatcher - IP validation', async () => {
|
||
|
expect(IpMatcher.isValidIpv4('192.168.1.1')).toEqual(true);
|
||
|
expect(IpMatcher.isValidIpv4('255.255.255.255')).toEqual(true);
|
||
|
expect(IpMatcher.isValidIpv4('0.0.0.0')).toEqual(true);
|
||
|
|
||
|
expect(IpMatcher.isValidIpv4('256.1.1.1')).toEqual(false);
|
||
|
expect(IpMatcher.isValidIpv4('1.1.1')).toEqual(false);
|
||
|
expect(IpMatcher.isValidIpv4('1.1.1.1.1')).toEqual(false);
|
||
|
expect(IpMatcher.isValidIpv4('1.1.1.a')).toEqual(false);
|
||
|
expect(IpMatcher.isValidIpv4('01.1.1.1')).toEqual(false); // No leading zeros
|
||
|
});
|
||
|
|
||
|
tap.test('IpMatcher - isAuthorized', async () => {
|
||
|
// Empty lists - allow all
|
||
|
expect(IpMatcher.isAuthorized('192.168.1.1')).toEqual(true);
|
||
|
|
||
|
// Allow list only
|
||
|
const allowList = ['192.168.1.0/24', '10.0.0.0/16'];
|
||
|
expect(IpMatcher.isAuthorized('192.168.1.100', allowList)).toEqual(true);
|
||
|
expect(IpMatcher.isAuthorized('10.0.50.1', allowList)).toEqual(true);
|
||
|
expect(IpMatcher.isAuthorized('172.16.0.1', allowList)).toEqual(false);
|
||
|
|
||
|
// Block list only
|
||
|
const blockList = ['192.168.1.100', '10.0.0.0/24'];
|
||
|
expect(IpMatcher.isAuthorized('192.168.1.100', [], blockList)).toEqual(false);
|
||
|
expect(IpMatcher.isAuthorized('10.0.0.50', [], blockList)).toEqual(false);
|
||
|
expect(IpMatcher.isAuthorized('192.168.1.101', [], blockList)).toEqual(true);
|
||
|
|
||
|
// Both lists - block takes precedence
|
||
|
expect(IpMatcher.isAuthorized('192.168.1.100', allowList, ['192.168.1.100'])).toEqual(false);
|
||
|
});
|
||
|
|
||
|
tap.test('IpMatcher - specificity calculation', async () => {
|
||
|
// Exact IPs are most specific
|
||
|
const exactScore = IpMatcher.calculateSpecificity('192.168.1.1');
|
||
|
const cidr32Score = IpMatcher.calculateSpecificity('192.168.1.1/32');
|
||
|
const cidr24Score = IpMatcher.calculateSpecificity('192.168.1.0/24');
|
||
|
const cidr16Score = IpMatcher.calculateSpecificity('192.168.0.0/16');
|
||
|
const wildcardScore = IpMatcher.calculateSpecificity('192.168.1.*');
|
||
|
const rangeScore = IpMatcher.calculateSpecificity('192.168.1.1-192.168.1.10');
|
||
|
|
||
|
expect(exactScore).toBeGreaterThan(cidr24Score);
|
||
|
expect(cidr32Score).toBeGreaterThan(cidr24Score);
|
||
|
expect(cidr24Score).toBeGreaterThan(cidr16Score);
|
||
|
expect(rangeScore).toBeGreaterThan(wildcardScore);
|
||
|
});
|
||
|
|
||
|
tap.test('IpMatcher - edge cases', async () => {
|
||
|
// Empty/null inputs
|
||
|
expect(IpMatcher.match('', '192.168.1.1')).toEqual(false);
|
||
|
expect(IpMatcher.match('192.168.1.1', '')).toEqual(false);
|
||
|
expect(IpMatcher.match(null as any, '192.168.1.1')).toEqual(false);
|
||
|
expect(IpMatcher.match('192.168.1.1', null as any)).toEqual(false);
|
||
|
|
||
|
// Invalid CIDR
|
||
|
expect(IpMatcher.match('192.168.1.0/33', '192.168.1.1')).toEqual(false);
|
||
|
expect(IpMatcher.match('192.168.1.0/-1', '192.168.1.1')).toEqual(false);
|
||
|
expect(IpMatcher.match('192.168.1.0/', '192.168.1.1')).toEqual(false);
|
||
|
|
||
|
// Invalid ranges
|
||
|
expect(IpMatcher.match('192.168.1.10-192.168.1.1', '192.168.1.5')).toEqual(false); // Start > end
|
||
|
expect(IpMatcher.match('192.168.1.1-', '192.168.1.5')).toEqual(false);
|
||
|
expect(IpMatcher.match('-192.168.1.10', '192.168.1.5')).toEqual(false);
|
||
|
});
|
||
|
|
||
|
tap.start();
|