amneziawg-schema-cleared.test.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import { describe, expect, it } from 'vitest';
  2. import { AmneziawgServerSchema } from '@/schemas/protocols/inbound/amneziawg';
  3. import { AmneziaWGOutboundSettingsSchema } from '@/schemas/protocols/outbound/amneziawg';
  4. // AntD InputNumber emits null when cleared; a cleared numeric field must
  5. // refill its schema default instead of failing validation and blocking the save.
  6. describe('AmneziawgServerSchema cleared numeric fields', () => {
  7. it('accepts null for every InputNumber-backed field and refills the default', () => {
  8. const parsed = AmneziawgServerSchema.parse({
  9. subnetCidr: null,
  10. jc: null,
  11. jmin: null,
  12. jmax: null,
  13. s1: null,
  14. s2: null,
  15. s3: null,
  16. s4: null,
  17. });
  18. expect(parsed.subnetCidr).toBe(24);
  19. expect(parsed.jc).toBe(5);
  20. expect(parsed.jmin).toBe(10);
  21. expect(parsed.jmax).toBe(50);
  22. expect(parsed.s1).toBe(30);
  23. expect(parsed.s2).toBe(45);
  24. expect(parsed.s3).toBe(10);
  25. expect(parsed.s4).toBe(5);
  26. });
  27. it('keeps absent-key defaults unchanged', () => {
  28. const parsed = AmneziawgServerSchema.parse({});
  29. expect(parsed.subnetCidr).toBe(24);
  30. expect(parsed.jc).toBe(5);
  31. });
  32. });
  33. // The form must reject what cannot apply or be received: jc/jmin/jmax past uint32 (device/uapi.go),
  34. // S1-S3 past amneziawg-go's 1700-byte iOS receive buffer, S4 past 32 (MTU headroom).
  35. describe('AmneziawgServerSchema obfuscation bounds', () => {
  36. const overWidth: Array<[string, number]> = [
  37. ['s1', 1553],
  38. ['s2', 1609],
  39. ['s3', 1637],
  40. ['s4', 33],
  41. ['jc', 4294967296],
  42. ['jmin', 4294967296],
  43. ['jmax', 5000000000],
  44. ];
  45. it.each(overWidth)('rejects %s past what amneziawg-go can apply or receive', (field, value) => {
  46. expect(AmneziawgServerSchema.safeParse({ [field]: value }).success).toBe(false);
  47. });
  48. const atLimit: Array<[string, number]> = [
  49. ['s1', 1552],
  50. ['s2', 1608],
  51. ['s3', 1636],
  52. ['s4', 32],
  53. ['jc', 4294967295],
  54. ];
  55. it.each(atLimit)('accepts %s exactly at its limit', (field, value) => {
  56. const parsed = AmneziawgServerSchema.safeParse({ [field]: value });
  57. expect(parsed.success).toBe(true);
  58. });
  59. it('still rejects negatives on every junk and padding field', () => {
  60. for (const field of ['jc', 'jmin', 'jmax', 's1', 's2', 's3', 's4']) {
  61. expect(AmneziawgServerSchema.safeParse({ [field]: -1 }).success).toBe(false);
  62. }
  63. });
  64. });
  65. // An outbound's S values come from the remote server and are received on Linux,
  66. // so only amneziawg-go's uint16 UAPI width bounds them, not the iOS buffer.
  67. describe('AmneziaWGOutboundSettingsSchema padding bounds', () => {
  68. it.each(['s1', 's2', 's3'])('accepts %s past the inbound iOS cap', (field) => {
  69. expect(AmneziaWGOutboundSettingsSchema.safeParse({ [field]: 2000 }).success).toBe(true);
  70. });
  71. it.each(['s1', 's2', 's3'])('rejects %s past uint16', (field) => {
  72. expect(AmneziaWGOutboundSettingsSchema.safeParse({ [field]: 65536 }).success).toBe(false);
  73. });
  74. });