180 lines
4.8 KiB
TypeScript
180 lines
4.8 KiB
TypeScript
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
|
import { VpnConfig } from '../ts/index.js';
|
|
import type { IVpnClientConfig, IVpnServerConfig } from '../ts/index.js';
|
|
|
|
// Valid 32-byte base64 keys for testing
|
|
const TEST_KEY_A = 'YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE=';
|
|
const TEST_KEY_B = 'YmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmI=';
|
|
const TEST_KEY_C = 'Y2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2M=';
|
|
|
|
tap.test('VpnConfig: validate valid client config', async () => {
|
|
const config: IVpnClientConfig = {
|
|
serverUrl: 'wss://vpn.example.com/tunnel',
|
|
serverPublicKey: TEST_KEY_A,
|
|
clientPrivateKey: TEST_KEY_B,
|
|
clientPublicKey: TEST_KEY_C,
|
|
dns: ['1.1.1.1', '8.8.8.8'],
|
|
mtu: 1420,
|
|
keepaliveIntervalSecs: 30,
|
|
};
|
|
// Should not throw
|
|
VpnConfig.validateClientConfig(config);
|
|
});
|
|
|
|
tap.test('VpnConfig: reject client config without serverUrl', async () => {
|
|
const config = {
|
|
serverPublicKey: TEST_KEY_A,
|
|
clientPrivateKey: TEST_KEY_B,
|
|
clientPublicKey: TEST_KEY_C,
|
|
} as IVpnClientConfig;
|
|
let threw = false;
|
|
try {
|
|
VpnConfig.validateClientConfig(config);
|
|
} catch (e) {
|
|
threw = true;
|
|
expect((e as Error).message).toContain('serverUrl');
|
|
}
|
|
expect(threw).toBeTrue();
|
|
});
|
|
|
|
tap.test('VpnConfig: reject client config with invalid serverUrl scheme', async () => {
|
|
const config: IVpnClientConfig = {
|
|
serverUrl: 'http://vpn.example.com/tunnel',
|
|
serverPublicKey: TEST_KEY_A,
|
|
clientPrivateKey: TEST_KEY_B,
|
|
clientPublicKey: TEST_KEY_C,
|
|
};
|
|
let threw = false;
|
|
try {
|
|
VpnConfig.validateClientConfig(config);
|
|
} catch (e) {
|
|
threw = true;
|
|
expect((e as Error).message).toContain('wss://');
|
|
}
|
|
expect(threw).toBeTrue();
|
|
});
|
|
|
|
tap.test('VpnConfig: reject client config without clientPrivateKey', async () => {
|
|
const config = {
|
|
serverUrl: 'wss://vpn.example.com/tunnel',
|
|
serverPublicKey: TEST_KEY_A,
|
|
clientPublicKey: TEST_KEY_C,
|
|
} as IVpnClientConfig;
|
|
let threw = false;
|
|
try {
|
|
VpnConfig.validateClientConfig(config);
|
|
} catch (e) {
|
|
threw = true;
|
|
expect((e as Error).message).toContain('clientPrivateKey');
|
|
}
|
|
expect(threw).toBeTrue();
|
|
});
|
|
|
|
tap.test('VpnConfig: reject client config with invalid MTU', async () => {
|
|
const config: IVpnClientConfig = {
|
|
serverUrl: 'wss://vpn.example.com/tunnel',
|
|
serverPublicKey: TEST_KEY_A,
|
|
clientPrivateKey: TEST_KEY_B,
|
|
clientPublicKey: TEST_KEY_C,
|
|
mtu: 100,
|
|
};
|
|
let threw = false;
|
|
try {
|
|
VpnConfig.validateClientConfig(config);
|
|
} catch (e) {
|
|
threw = true;
|
|
expect((e as Error).message).toContain('mtu');
|
|
}
|
|
expect(threw).toBeTrue();
|
|
});
|
|
|
|
tap.test('VpnConfig: reject client config with invalid DNS', async () => {
|
|
const config: IVpnClientConfig = {
|
|
serverUrl: 'wss://vpn.example.com/tunnel',
|
|
serverPublicKey: TEST_KEY_A,
|
|
clientPrivateKey: TEST_KEY_B,
|
|
clientPublicKey: TEST_KEY_C,
|
|
dns: ['not-an-ip'],
|
|
};
|
|
let threw = false;
|
|
try {
|
|
VpnConfig.validateClientConfig(config);
|
|
} catch (e) {
|
|
threw = true;
|
|
expect((e as Error).message).toContain('DNS');
|
|
}
|
|
expect(threw).toBeTrue();
|
|
});
|
|
|
|
tap.test('VpnConfig: validate valid server config', async () => {
|
|
const config: IVpnServerConfig = {
|
|
listenAddr: '0.0.0.0:443',
|
|
privateKey: TEST_KEY_A,
|
|
publicKey: TEST_KEY_B,
|
|
subnet: '10.8.0.0/24',
|
|
dns: ['1.1.1.1'],
|
|
mtu: 1420,
|
|
enableNat: true,
|
|
clients: [
|
|
{ clientId: 'test-client', publicKey: TEST_KEY_C },
|
|
],
|
|
};
|
|
// Should not throw
|
|
VpnConfig.validateServerConfig(config);
|
|
});
|
|
|
|
tap.test('VpnConfig: reject server config with invalid subnet', async () => {
|
|
const config: IVpnServerConfig = {
|
|
listenAddr: '0.0.0.0:443',
|
|
privateKey: TEST_KEY_A,
|
|
publicKey: TEST_KEY_B,
|
|
subnet: 'invalid',
|
|
};
|
|
let threw = false;
|
|
try {
|
|
VpnConfig.validateServerConfig(config);
|
|
} catch (e) {
|
|
threw = true;
|
|
expect((e as Error).message).toContain('subnet');
|
|
}
|
|
expect(threw).toBeTrue();
|
|
});
|
|
|
|
tap.test('VpnConfig: reject server config without privateKey', async () => {
|
|
const config = {
|
|
listenAddr: '0.0.0.0:443',
|
|
publicKey: TEST_KEY_B,
|
|
subnet: '10.8.0.0/24',
|
|
} as IVpnServerConfig;
|
|
let threw = false;
|
|
try {
|
|
VpnConfig.validateServerConfig(config);
|
|
} catch (e) {
|
|
threw = true;
|
|
expect((e as Error).message).toContain('privateKey');
|
|
}
|
|
expect(threw).toBeTrue();
|
|
});
|
|
|
|
tap.test('VpnConfig: reject server config with invalid client publicKey', async () => {
|
|
const config: IVpnServerConfig = {
|
|
listenAddr: '0.0.0.0:443',
|
|
privateKey: TEST_KEY_A,
|
|
publicKey: TEST_KEY_B,
|
|
subnet: '10.8.0.0/24',
|
|
clients: [
|
|
{ clientId: 'bad-client', publicKey: 'short-key' },
|
|
],
|
|
};
|
|
let threw = false;
|
|
try {
|
|
VpnConfig.validateServerConfig(config);
|
|
} catch (e) {
|
|
threw = true;
|
|
expect((e as Error).message).toContain('publicKey');
|
|
}
|
|
expect(threw).toBeTrue();
|
|
});
|
|
|
|
export default tap.start();
|