amneziawg-outbound-adapter.test.ts 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { describe, expect, it } from 'vitest';
  2. import { formValuesToWirePayload, rawOutboundToFormValues } from '@/lib/xray/outbound-form-adapter';
  3. import type { AmneziaWGOutboundFormSettings } from '@/schemas/forms/outbound-form';
  4. // amneziawg outbound: lossless form->wire->form; payload stays a raw row.
  5. describe('amneziawg outbound adapter', () => {
  6. const wire = {
  7. mtu: 1380,
  8. secretKey: '6Nn0ZB4C1Pj3TBEsXgLv7VdmSnYXGxS+HhVBDhvGgHE=',
  9. address: ['10.8.0.2/32'],
  10. listenPort: 40001,
  11. jc: 5,
  12. jmin: 40,
  13. jmax: 90,
  14. s1: 20,
  15. s2: 90,
  16. s3: 15,
  17. s4: 13,
  18. h1: '100-800',
  19. h2: '900-1600',
  20. h3: '1700-2400',
  21. h4: '2500-3200',
  22. i1: '<r 64>',
  23. contentPaddingAddition: '8-40',
  24. randomTrailers: true,
  25. disableCookies: false,
  26. peers: [
  27. {
  28. publicKey: 'Qk9fWqDqC7LzKpYvJq0m2b1tq8eF3uY6oPpRrSsTtUu=',
  29. presharedKey: 'cHNo',
  30. allowedIPs: ['0.0.0.0/0', '::/0'],
  31. endpoint: '203.0.113.7:51820',
  32. keepAlive: 25,
  33. },
  34. ],
  35. };
  36. it('hydrates defaults when the template omits optional keys', () => {
  37. const values = rawOutboundToFormValues({ protocol: 'amneziawg', tag: 'awg-x' });
  38. expect(values.protocol).toBe('amneziawg');
  39. const s = values.settings as AmneziaWGOutboundFormSettings;
  40. expect(s.mtu).toBe(0);
  41. expect(s.randomTrailers).toBe(false);
  42. expect(s.disableCookies).toBe(true);
  43. expect(s.peers).toEqual([]);
  44. expect(values.tag).toBe('awg-x');
  45. });
  46. // A blank MTU must reach the backend absent, not pinned to 1420: the Go
  47. // EffectiveMTU subtracts S4 from the default only when the field is unset.
  48. it('leaves a defaulted MTU out of the payload so the backend derives it', () => {
  49. const values = rawOutboundToFormValues({ protocol: 'amneziawg', tag: 'awg-x' });
  50. const payload = formValuesToWirePayload(values);
  51. expect((payload.settings as Record<string, unknown>).mtu).toBeUndefined();
  52. });
  53. it('round-trips wire -> form -> wire losslessly', () => {
  54. const values = rawOutboundToFormValues({ protocol: 'amneziawg', tag: 'awg-x', settings: wire });
  55. const payload = formValuesToWirePayload(values);
  56. expect(payload.protocol).toBe('amneziawg');
  57. expect(payload.tag).toBe('awg-x');
  58. // undefined-valued optionals are dropped by JSON semantics; compare the
  59. // meaningful fields directly.
  60. expect((payload.settings as Record<string, unknown>).mtu).toBe(1380);
  61. expect((payload.settings as Record<string, unknown>).listenPort).toBe(40001);
  62. expect((payload.settings as Record<string, unknown>).i1).toBe('<r 64>');
  63. expect((payload.settings as Record<string, unknown>).peers).toEqual(wire.peers);
  64. expect((payload.settings as Record<string, unknown>).disableCookies).toBe(false);
  65. });
  66. it('omits empty optional strings and zero listenPort from the payload', () => {
  67. const values = rawOutboundToFormValues({ protocol: 'amneziawg', settings: wire });
  68. const awg = values.settings as AmneziaWGOutboundFormSettings;
  69. awg.i1 = '';
  70. awg.listenPort = 0;
  71. const payload = formValuesToWirePayload(values);
  72. const s = payload.settings as Record<string, unknown>;
  73. expect(s.i1).toBeUndefined();
  74. expect(s.listenPort).toBeUndefined();
  75. // always-present booleans survive so a true->false edit is diffable
  76. expect(s.randomTrailers).toBe(true);
  77. });
  78. it('is included in every protocol-capability gate like wireguard (non-stream, non-mux)', () => {
  79. const values = rawOutboundToFormValues({
  80. protocol: 'amneziawg',
  81. settings: wire,
  82. streamSettings: { network: 'tcp', tcpSettings: {} },
  83. });
  84. const payload = formValuesToWirePayload(values);
  85. // Non-stream protocol keeps only sockopt; here there is none.
  86. expect(payload.streamSettings).toBeUndefined();
  87. });
  88. });