You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

234 lines
6.2 KiB

import { describe, expect, test, vi } from 'vitest';
import { resolveClientEffectivePolicy } from '#shared/utils/clientPolicy';
import { firewallTestExports } from '#server/utils/firewall';
import { wg } from '#server/utils/wgHelper';
import type { ClientType } from '#db/repositories/client/types';
import type { InterfaceType } from '#db/repositories/interface/types';
import type { UserConfigType } from '#db/repositories/userConfig/types';
vi.mock('#server/utils/config', () => ({
WG_ENV: {
WG_EXECUTABLE: 'wg',
DISABLE_IPV6: false,
},
}));
const userConfig = {
defaultAllowedIps: ['0.0.0.0/0'],
defaultDns: ['1.1.1.1'],
host: 'vpn.example.test',
port: 51820,
} as UserConfigType;
const wgInterface = {
publicKey: 'server-public-key',
firewallEnabled: true,
} as InterfaceType;
function createClient(overrides: Partial<ClientType> = {}) {
return {
id: 1,
name: 'Phone',
ipv4Address: '10.8.0.2',
ipv6Address: 'fd00::2',
privateKey: 'client-private-key',
publicKey: 'client-public-key',
preSharedKey: 'client-preshared-key',
allowedIps: null,
dns: null,
firewallIps: null,
serverAllowedIps: ['192.168.50.0/24'],
preUp: '',
postUp: '',
preDown: '',
postDown: '',
mtu: 1420,
jC: null,
jMin: null,
jMax: null,
i1: null,
i2: null,
i3: null,
i4: null,
i5: null,
persistentKeepalive: 25,
serverEndpoint: null,
enabled: true,
userId: 1,
interfaceId: 'wg0',
expiresAt: null,
createdAt: '2026-01-01 00:00:00',
updatedAt: '2026-01-01 00:00:00',
...overrides,
} as ClientType;
}
describe('client group effective policy', () => {
test('ungrouped clients preserve client and global fallback behavior', () => {
const policy = resolveClientEffectivePolicy({
client: createClient({
allowedIps: ['10.10.0.0/24'],
dns: null,
firewallIps: null,
}),
groups: [],
userConfig,
firewallEnabled: true,
});
expect(policy.allowedIps).toEqual(['10.10.0.0/24']);
expect(policy.dns).toEqual(['1.1.1.1']);
expect(policy.firewallIps).toEqual(['10.10.0.0/24']);
expect(policy.fields.allowedIps.source).toBe('client');
expect(policy.fields.dns.source).toBe('global');
});
test('combines multiple contributing groups in membership and entry order', () => {
const client = createClient({
allowedIps: ['10.10.0.0/24'],
dns: ['9.9.9.9'],
firewallIps: ['10.10.0.10:443/tcp'],
});
const policy = resolveClientEffectivePolicy({
client,
groups: [
{
id: 1,
name: 'Customers',
allowedIps: ['10.20.0.0/24', '172.16.0.10/32'],
dns: ['8.8.8.8'],
firewallIps: ['10.20.0.10:443/tcp'],
},
{
id: 2,
name: 'NAS',
allowedIps: ['172.16.0.10/32', '192.0.2.10/32'],
dns: ['1.0.0.1', '8.8.8.8'],
firewallIps: ['10.20.0.10:443/tcp', '10.30.0.10:443/tcp'],
},
],
userConfig,
firewallEnabled: true,
});
expect(policy.allowedIps).toEqual([
'10.20.0.0/24',
'172.16.0.10/32',
'192.0.2.10/32',
]);
expect(policy.dns).toEqual(['8.8.8.8', '1.0.0.1']);
expect(policy.firewallIps).toEqual([
'10.20.0.10:443/tcp',
'10.30.0.10:443/tcp',
]);
expect(policy.fields.allowedIps.groups).toEqual([
{ id: 1, name: 'Customers' },
{ id: 2, name: 'NAS' },
]);
});
test('grouped clients ignore individual values and fall back to global when no group contributes', () => {
const policy = resolveClientEffectivePolicy({
client: createClient({
allowedIps: ['10.10.0.0/24'],
dns: ['9.9.9.9'],
firewallIps: ['10.10.0.10:443/tcp'],
}),
groups: [
{
id: 1,
name: 'Empty Legacy',
allowedIps: [],
dns: [],
firewallIps: [],
},
{
id: 2,
name: 'No Policy',
allowedIps: null,
dns: null,
firewallIps: null,
},
],
userConfig,
firewallEnabled: true,
});
expect(policy.allowedIps).toEqual(['0.0.0.0/0']);
expect(policy.dns).toEqual(['1.1.1.1']);
expect(policy.firewallIps).toEqual(['0.0.0.0/0']);
expect(policy.fields.allowedIps.source).toBe('global');
expect(policy.groupManagedAllowedIps).toBe(false);
});
test('generated config uses group union without changing server peer routes', () => {
const client = createClient({
allowedIps: ['10.10.0.0/24'],
dns: ['9.9.9.9'],
});
const policy = resolveClientEffectivePolicy({
client,
groups: [
{
id: 1,
name: 'Customers',
allowedIps: ['10.20.0.0/24'],
dns: ['8.8.8.8'],
firewallIps: null,
},
],
userConfig,
firewallEnabled: true,
});
const config = wg.generateClientConfig(wgInterface, userConfig, client, {
effectivePolicy: policy,
});
const serverPeer = wg.generateServerPeer(client);
expect(config).toContain('AllowedIPs = 10.20.0.0/24');
expect(config).toContain('DNS = 8.8.8.8');
expect(serverPeer).toContain(
'AllowedIPs = 10.8.0.2/32, fd00::2/128, 192.168.50.0/24'
);
expect(serverPeer).not.toContain('10.20.0.0/24');
});
test('firewall runtime uses group unions while enabled and ignores groups while disabled', () => {
const client = createClient({
allowedIps: ['10.10.0.0/24'],
firewallIps: ['10.10.0.10:443/tcp'],
});
const groups = [
{
id: 1,
name: 'Customers',
allowedIps: null,
dns: null,
firewallIps: ['10.20.0.10:443/tcp'],
},
{
id: 2,
name: 'NAS',
allowedIps: null,
dns: null,
firewallIps: ['10.20.0.10:443/tcp', '10.30.0.10:443/tcp'],
},
];
expect(
firewallTestExports.resolveFirewallClientIps(client, userConfig, groups)
).toEqual(['10.20.0.10:443/tcp', '10.30.0.10:443/tcp']);
const disabledPolicy = resolveClientEffectivePolicy({
client,
groups,
userConfig,
firewallEnabled: false,
});
expect(disabledPolicy.firewallIps).toEqual([]);
expect(disabledPolicy.groupManagedFirewallIps).toBe(false);
});
});