import { tap, expect } from '@git.zone/tstest/tapbundle'; import { VpnConfig, VpnServer, WgConfigGenerator, } from '../ts/index.js'; import type { IVpnClientConfig, IVpnServerConfig, IVpnServerOptions, IWgPeerConfig, } from '../ts/index.js'; // ============================================================================ // WireGuard config validation — client // ============================================================================ // A valid 32-byte key in base64 (44 chars) const VALID_KEY = 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='; const VALID_KEY_2 = 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB='; tap.test('WG client config: valid wireguard config passes validation', async () => { const config: IVpnClientConfig = { serverUrl: '', // not needed for WG serverPublicKey: VALID_KEY, transport: 'wireguard', wgPrivateKey: VALID_KEY_2, wgAddress: '10.8.0.2', wgEndpoint: 'vpn.example.com:51820', wgAllowedIps: ['0.0.0.0/0'], }; VpnConfig.validateClientConfig(config); }); tap.test('WG client config: rejects missing wgPrivateKey', async () => { const config: IVpnClientConfig = { serverUrl: '', serverPublicKey: VALID_KEY, transport: 'wireguard', wgAddress: '10.8.0.2', wgEndpoint: 'vpn.example.com:51820', }; let threw = false; try { VpnConfig.validateClientConfig(config); } catch (e) { threw = true; expect((e as Error).message).toContain('wgPrivateKey'); } expect(threw).toBeTrue(); }); tap.test('WG client config: rejects missing wgAddress', async () => { const config: IVpnClientConfig = { serverUrl: '', serverPublicKey: VALID_KEY, transport: 'wireguard', wgPrivateKey: VALID_KEY_2, wgEndpoint: 'vpn.example.com:51820', }; let threw = false; try { VpnConfig.validateClientConfig(config); } catch (e) { threw = true; expect((e as Error).message).toContain('wgAddress'); } expect(threw).toBeTrue(); }); tap.test('WG client config: rejects missing wgEndpoint', async () => { const config: IVpnClientConfig = { serverUrl: '', serverPublicKey: VALID_KEY, transport: 'wireguard', wgPrivateKey: VALID_KEY_2, wgAddress: '10.8.0.2', }; let threw = false; try { VpnConfig.validateClientConfig(config); } catch (e) { threw = true; expect((e as Error).message).toContain('wgEndpoint'); } expect(threw).toBeTrue(); }); tap.test('WG client config: rejects invalid key length', async () => { const config: IVpnClientConfig = { serverUrl: '', serverPublicKey: VALID_KEY, transport: 'wireguard', wgPrivateKey: 'tooshort', wgAddress: '10.8.0.2', wgEndpoint: 'vpn.example.com:51820', }; let threw = false; try { VpnConfig.validateClientConfig(config); } catch (e) { threw = true; expect((e as Error).message).toContain('44 characters'); } expect(threw).toBeTrue(); }); tap.test('WG client config: rejects invalid CIDR in allowedIps', async () => { const config: IVpnClientConfig = { serverUrl: '', serverPublicKey: VALID_KEY, transport: 'wireguard', wgPrivateKey: VALID_KEY_2, wgAddress: '10.8.0.2', wgEndpoint: 'vpn.example.com:51820', wgAllowedIps: ['not-a-cidr'], }; let threw = false; try { VpnConfig.validateClientConfig(config); } catch (e) { threw = true; expect((e as Error).message).toContain('CIDR'); } expect(threw).toBeTrue(); }); // ============================================================================ // WireGuard config validation — server // ============================================================================ tap.test('WG server config: valid config passes validation', async () => { const config: IVpnServerConfig = { listenAddr: '', privateKey: VALID_KEY, publicKey: VALID_KEY_2, subnet: '10.8.0.0/24', transportMode: 'wireguard', wgPeers: [ { publicKey: VALID_KEY_2, allowedIps: ['10.8.0.2/32'], }, ], }; VpnConfig.validateServerConfig(config); }); tap.test('WG server config: rejects empty wgPeers', async () => { const config: IVpnServerConfig = { listenAddr: '', privateKey: VALID_KEY, publicKey: VALID_KEY_2, subnet: '10.8.0.0/24', transportMode: 'wireguard', wgPeers: [], }; let threw = false; try { VpnConfig.validateServerConfig(config); } catch (e) { threw = true; expect((e as Error).message).toContain('wgPeers'); } expect(threw).toBeTrue(); }); tap.test('WG server config: rejects peer without publicKey', async () => { const config: IVpnServerConfig = { listenAddr: '', privateKey: VALID_KEY, publicKey: VALID_KEY_2, subnet: '10.8.0.0/24', transportMode: 'wireguard', wgPeers: [ { publicKey: '', allowedIps: ['10.8.0.2/32'], }, ], }; let threw = false; try { VpnConfig.validateServerConfig(config); } catch (e) { threw = true; expect((e as Error).message).toContain('publicKey'); } expect(threw).toBeTrue(); }); tap.test('WG server config: rejects invalid wgListenPort', async () => { const config: IVpnServerConfig = { listenAddr: '', privateKey: VALID_KEY, publicKey: VALID_KEY_2, subnet: '10.8.0.0/24', transportMode: 'wireguard', wgListenPort: 0, wgPeers: [ { publicKey: VALID_KEY_2, allowedIps: ['10.8.0.2/32'], }, ], }; let threw = false; try { VpnConfig.validateServerConfig(config); } catch (e) { threw = true; expect((e as Error).message).toContain('wgListenPort'); } expect(threw).toBeTrue(); }); // ============================================================================ // WireGuard keypair generation via daemon // ============================================================================ let server: VpnServer; tap.test('WG: spawn server daemon for keypair generation', async () => { const options: IVpnServerOptions = { transport: { transport: 'stdio' }, }; server = new VpnServer(options); const started = await server['bridge'].start(); expect(started).toBeTrue(); expect(server.running).toBeTrue(); }); tap.test('WG: generateWgKeypair returns valid keypair', async () => { const keypair = await server.generateWgKeypair(); expect(keypair.publicKey).toBeTypeofString(); expect(keypair.privateKey).toBeTypeofString(); // WireGuard keys: base64 of 32 bytes = 44 characters expect(keypair.publicKey.length).toEqual(44); expect(keypair.privateKey.length).toEqual(44); // Verify they decode to 32 bytes const pubBuf = Buffer.from(keypair.publicKey, 'base64'); const privBuf = Buffer.from(keypair.privateKey, 'base64'); expect(pubBuf.length).toEqual(32); expect(privBuf.length).toEqual(32); }); tap.test('WG: generateWgKeypair returns unique keys each time', async () => { const kp1 = await server.generateWgKeypair(); const kp2 = await server.generateWgKeypair(); expect(kp1.publicKey).not.toEqual(kp2.publicKey); expect(kp1.privateKey).not.toEqual(kp2.privateKey); }); tap.test('WG: stop server daemon', async () => { server.stop(); await new Promise((resolve) => setTimeout(resolve, 500)); expect(server.running).toBeFalse(); }); // ============================================================================ // WireGuard config file generation // ============================================================================ tap.test('WgConfigGenerator: generate client config', async () => { const conf = WgConfigGenerator.generateClientConfig({ privateKey: 'clientPrivateKeyBase64====================', address: '10.8.0.2/24', dns: ['1.1.1.1', '8.8.8.8'], mtu: 1420, peer: { publicKey: 'serverPublicKeyBase64====================', endpoint: 'vpn.example.com:51820', allowedIps: ['0.0.0.0/0', '::/0'], persistentKeepalive: 25, }, }); expect(conf).toContain('[Interface]'); expect(conf).toContain('PrivateKey = clientPrivateKeyBase64===================='); expect(conf).toContain('Address = 10.8.0.2/24'); expect(conf).toContain('DNS = 1.1.1.1, 8.8.8.8'); expect(conf).toContain('MTU = 1420'); expect(conf).toContain('[Peer]'); expect(conf).toContain('PublicKey = serverPublicKeyBase64===================='); expect(conf).toContain('Endpoint = vpn.example.com:51820'); expect(conf).toContain('AllowedIPs = 0.0.0.0/0, ::/0'); expect(conf).toContain('PersistentKeepalive = 25'); }); tap.test('WgConfigGenerator: generate client config without optional fields', async () => { const conf = WgConfigGenerator.generateClientConfig({ privateKey: 'key1', address: '10.0.0.2/32', peer: { publicKey: 'key2', endpoint: 'server:51820', allowedIps: ['10.0.0.0/24'], }, }); expect(conf).toContain('[Interface]'); expect(conf).not.toContain('DNS'); expect(conf).not.toContain('MTU'); expect(conf).not.toContain('PresharedKey'); expect(conf).not.toContain('PersistentKeepalive'); }); tap.test('WgConfigGenerator: generate server config with NAT', async () => { const conf = WgConfigGenerator.generateServerConfig({ privateKey: 'serverPrivKey', address: '10.8.0.1/24', listenPort: 51820, dns: ['1.1.1.1'], enableNat: true, natInterface: 'ens3', peers: [ { publicKey: 'peer1PubKey', allowedIps: ['10.8.0.2/32'], presharedKey: 'psk1', persistentKeepalive: 25, }, { publicKey: 'peer2PubKey', allowedIps: ['10.8.0.3/32'], }, ], }); expect(conf).toContain('[Interface]'); expect(conf).toContain('ListenPort = 51820'); expect(conf).toContain('PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE'); expect(conf).toContain('PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE'); // Two [Peer] sections const peerCount = (conf.match(/\[Peer\]/g) || []).length; expect(peerCount).toEqual(2); expect(conf).toContain('PresharedKey = psk1'); }); tap.test('WgConfigGenerator: generate server config without NAT', async () => { const conf = WgConfigGenerator.generateServerConfig({ privateKey: 'serverPrivKey', address: '10.8.0.1/24', listenPort: 51820, peers: [ { publicKey: 'peerKey', allowedIps: ['10.8.0.2/32'], }, ], }); expect(conf).not.toContain('PostUp'); expect(conf).not.toContain('PostDown'); }); export default tap.start();