wireguard.ts 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { z } from 'zod';
  2. export const WireguardDomainStrategySchema = z.enum([
  3. 'ForceIP',
  4. 'ForceIPv4',
  5. 'ForceIPv4v6',
  6. 'ForceIPv6',
  7. 'ForceIPv6v4',
  8. ]);
  9. export type WireguardDomainStrategy = z.infer<typeof WireguardDomainStrategySchema>;
  10. // AntD InputNumber emits null (not undefined) when the user clears it, and
  11. // the form store hands that null straight to safeParse on submit — a bare
  12. // .optional() would reject it and block the save.
  13. const optionalClearedInt = (schema: z.ZodNumber) =>
  14. z.preprocess((v) => (v == null ? undefined : v), schema.optional());
  15. // Wireguard inbound is peer-based (no clients). Each peer is a client device
  16. // the server accepts; secretKey is the server-side private key and pubKey is
  17. // derived from it at runtime (not persisted on the wire). Inbound peers
  18. // optionally store the client's privateKey so the panel can render configs
  19. // for the user — outbound peers never have a privateKey.
  20. export const WireguardInboundPeerSchema = z.object({
  21. privateKey: z.string().optional(),
  22. publicKey: z.string().min(1),
  23. preSharedKey: z.string().optional(),
  24. allowedIPs: z.array(z.string()).default([]),
  25. keepAlive: optionalClearedInt(z.number().int().min(0)),
  26. // Panel-only annotation (#5168): which client/device this peer belongs to.
  27. // Rides along in the settings JSON like privateKey does; xray-core ignores
  28. // unknown peer fields.
  29. comment: z.string().optional(),
  30. });
  31. export type WireguardInboundPeer = z.infer<typeof WireguardInboundPeerSchema>;
  32. // A WireGuard inbound client (multi-client model). Each client is one peer the
  33. // server accepts: the panel stores its keypair so it can render a full .conf/QR,
  34. // and allowedIPs is the client's unique tunnel address (allocated server-side
  35. // when left blank). Keys are optional on the wire — the backend generates them
  36. // when absent.
  37. export const WireguardClientSchema = z.object({
  38. privateKey: z.string().optional(),
  39. publicKey: z.string().optional(),
  40. preSharedKey: z.string().optional(),
  41. allowedIPs: z.array(z.string()).default([]),
  42. keepAlive: optionalClearedInt(z.number().int().min(0)),
  43. email: z.string().min(1),
  44. limitIp: z.number().int().min(0).default(0),
  45. totalGB: z.number().int().min(0).default(0),
  46. expiryTime: z.number().int().default(0),
  47. enable: z.boolean().default(true),
  48. tgId: z
  49. .union([z.number(), z.string()])
  50. .transform((v) => Number(v) || 0)
  51. .default(0),
  52. subId: z.string().default(''),
  53. comment: z.string().default(''),
  54. reset: z.number().int().min(0).default(0),
  55. created_at: z.number().int().optional(),
  56. updated_at: z.number().int().optional(),
  57. });
  58. export type WireguardClient = z.infer<typeof WireguardClientSchema>;
  59. export const WireguardInboundSettingsSchema = z.object({
  60. mtu: optionalClearedInt(z.number().int().min(1)),
  61. secretKey: z.string().min(1),
  62. dns: z.string().optional(),
  63. peers: z.array(WireguardInboundPeerSchema).default([]),
  64. clients: z.array(WireguardClientSchema).default([]),
  65. noKernelTun: z.boolean().default(false),
  66. domainStrategy: WireguardDomainStrategySchema.optional(),
  67. // Admin-configurable base subnet new clients are auto-allocated from —
  68. // mirrors AmneziaWG's settings.server.subnetIp/subnetCidr. Optional and
  69. // left blank by default: an inbound that never sets this keeps the
  70. // pre-existing behavior (infer from existing clients' own addresses, else
  71. // fall back to 10.0.0.0/24 server-side).
  72. subnetIp: z.string().default(''),
  73. subnetCidr: optionalClearedInt(z.number().int().min(1).max(32)),
  74. });
  75. export type WireguardInboundSettings = z.infer<typeof WireguardInboundSettingsSchema>;