| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- import { describe, it, expect } from 'vitest';
- import { genAmneziaWGConfig } from '@/lib/xray/inbound-link';
- import { buildAmneziaWGClientConfig } from '@/pages/clients/amneziawgConfig';
- import type { AmneziawgInboundSettings } from '@/schemas/protocols/inbound/amneziawg';
- import type { ClientRecord, InboundOption } from '@/hooks/useClients';
- // wg-quick(8)'s own peer order. The panel emits an AmneziaWG .conf from three
- // independent places (this file's two, plus amneziaWGConfigText in Go), and a
- // user comparing a subscription link against a downloaded .conf sees any drift
- // between them immediately.
- const PEER_FIELD_ORDER = [
- 'PublicKey',
- 'PresharedKey',
- 'AllowedIPs',
- 'Endpoint',
- 'PersistentKeepalive',
- ];
- function peerFields(conf: string): string[] {
- const peerBlock = conf.slice(conf.indexOf('[Peer]'));
- return peerBlock
- .split('\n')
- .map((line) => line.split('=')[0].trim())
- .filter((key) => PEER_FIELD_ORDER.includes(key));
- }
- describe('AmneziaWG .conf emitters agree on the peer block', () => {
- const settings = {
- server: {
- publicKey: 'serverPubKey==',
- primaryDns: '8.8.8.8',
- secondaryDns: '',
- mtu: 1420,
- jc: 4,
- jmin: 40,
- jmax: 100,
- s1: 30,
- s2: 90,
- s3: 0,
- s4: 0,
- h1: '',
- h2: '',
- h3: '',
- h4: '',
- },
- clients: [
- {
- email: 'peer-1',
- privateKey: 'clientPrivKey==',
- allowedIPs: ['10.8.1.2/32'],
- preSharedKey: 'psk==',
- keepAlive: 25,
- },
- ],
- } as unknown as AmneziawgInboundSettings;
- const linkConf = genAmneziaWGConfig({
- settings,
- address: 'awg.example.test',
- port: 51820,
- remark: 'awg-peer-1',
- peerIndex: 0,
- });
- const client = {
- email: 'peer-1',
- privateKey: 'clientPrivKey==',
- allowedIPs: '10.8.1.2/32',
- preSharedKey: 'psk==',
- keepAlive: 25,
- } as unknown as ClientRecord;
- const inbound = {
- id: 1,
- tag: 'awg-1',
- remark: 'awg',
- port: 51820,
- protocol: 'amneziawg',
- awgServer: settings.server,
- } as unknown as InboundOption;
- const clientsPageConf = buildAmneziaWGClientConfig(client, inbound, 'awg.example.test');
- it('the share-link emitter uses the wg-quick peer order', () => {
- expect(peerFields(linkConf)).toEqual(PEER_FIELD_ORDER);
- });
- it('the clients-page emitter uses the same order', () => {
- expect(peerFields(clientsPageConf)).toEqual(PEER_FIELD_ORDER);
- });
- it('neither emitter leaves a trailing newline, so both end on their last set field', () => {
- expect(linkConf.endsWith('\n')).toBe(false);
- expect(clientsPageConf.endsWith('\n')).toBe(false);
- });
- it('an unset preSharedKey drops the line in both, without disturbing the rest', () => {
- const noPsk = {
- ...settings,
- clients: [{ ...settings.clients[0], preSharedKey: '' }],
- } as AmneziawgInboundSettings;
- const withoutPsk = genAmneziaWGConfig({
- settings: noPsk,
- address: 'awg.example.test',
- port: 51820,
- remark: 'awg-peer-1',
- peerIndex: 0,
- });
- const clientWithoutPsk = { ...client, preSharedKey: '' } as unknown as ClientRecord;
- const want = PEER_FIELD_ORDER.filter((f) => f !== 'PresharedKey');
- expect(peerFields(withoutPsk)).toEqual(want);
- expect(
- peerFields(buildAmneziaWGClientConfig(clientWithoutPsk, inbound, 'awg.example.test')),
- ).toEqual(want);
- });
- });
- // s4 junk is prepended to every transport packet and never clamped to the MTU,
- // so both emitters must write the same S4-aware value the server interface uses.
- describe('AmneziaWG .conf emitters agree on MTU', () => {
- function build(mtu: number | undefined, s4: number) {
- const settings = {
- server: {
- publicKey: 'serverPubKey==',
- primaryDns: '8.8.8.8',
- secondaryDns: '',
- mtu,
- jc: 4,
- jmin: 40,
- jmax: 100,
- s1: 30,
- s2: 90,
- s3: 0,
- s4,
- h1: '',
- h2: '',
- h3: '',
- h4: '',
- },
- clients: [{ email: 'peer-1', privateKey: 'clientPrivKey==', allowedIPs: ['10.8.1.2/32'] }],
- } as unknown as AmneziawgInboundSettings;
- const link = genAmneziaWGConfig({
- settings,
- address: 'awg.example.test',
- port: 51820,
- remark: 'awg-peer-1',
- peerIndex: 0,
- });
- const download = buildAmneziaWGClientConfig(
- {
- email: 'peer-1',
- privateKey: 'clientPrivKey==',
- allowedIPs: '10.8.1.2/32',
- } as unknown as ClientRecord,
- {
- id: 1,
- tag: 'awg-1',
- remark: 'awg',
- protocol: 'amneziawg',
- port: 51820,
- awgServer: settings.server,
- } as unknown as InboundOption,
- 'awg.example.test',
- );
- return { link, download };
- }
- function mtuLine(conf: string): string | undefined {
- return conf.split('\n').find((l) => l.startsWith('MTU = '));
- }
- it('always emits an MTU, even when the inbound has none set', () => {
- const { link, download } = build(undefined, 27);
- // 1420 - 27: without this the client stays on its own 1420 default and
- // fragments every full-size packet it sends.
- expect(mtuLine(link)).toBe('MTU = 1393');
- expect(mtuLine(download)).toBe('MTU = 1393');
- });
- it('keeps an explicit MTU untouched', () => {
- const { link, download } = build(1380, 27);
- expect(mtuLine(link)).toBe('MTU = 1380');
- expect(mtuLine(download)).toBe('MTU = 1380');
- });
- it('falls back to the plain default when there is no s4', () => {
- const { link, download } = build(undefined, 0);
- expect(mtuLine(link)).toBe('MTU = 1420');
- expect(mtuLine(download)).toBe('MTU = 1420');
- });
- });
|