| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- import { z } from 'zod';
- // AntD InputNumber emits null (not undefined) when the user clears it, and
- // the form store hands that null straight to safeParse on submit — a bare
- // .optional() would reject it and block the save.
- const optionalClearedInt = (schema: z.ZodNumber) =>
- z.preprocess((v) => (v == null ? undefined : v), schema.optional());
- // Same null-absorbing preprocess for fields that keep a schema default:
- // clearing the InputNumber refills the default instead of blocking the save.
- const clearedToDefault = <T extends z.ZodType>(schema: T) =>
- z.preprocess((v) => (v == null ? undefined : v), schema);
- // An AmneziaWG client (multi-client model). Same key/address fields as
- // WireguardClientSchema — the panel's generic ClientRecord already has those
- // exact keys (privateKey/publicKey/preSharedKey/allowedIPs/keepAlive), so
- // bulk operations, the QR modal and subscriptions all work unmodified — plus
- // one AmneziaWG-only addition, forwardedPorts (WireGuard's Xray-native
- // inbound has no host-level iptables layer to hang per-client DNAT off of).
- // Keys are optional on the wire — the backend generates them when absent.
- export const AmneziawgClientSchema = z.object({
- privateKey: z.string().optional(),
- publicKey: z.string().optional(),
- preSharedKey: z.string().optional(),
- allowedIPs: z.array(z.string()).default([]),
- keepAlive: optionalClearedInt(z.number().int().min(0)),
- forwardedPorts: z.string().default(''),
- email: z.string().min(1),
- limitIp: z.number().int().min(0).default(0),
- totalGB: z.number().int().min(0).default(0),
- expiryTime: z.number().int().default(0),
- enable: z.boolean().default(true),
- tgId: z
- .union([z.number(), z.string()])
- .transform((v) => Number(v) || 0)
- .default(0),
- subId: z.string().default(''),
- comment: z.string().default(''),
- reset: z.number().int().min(0).default(0),
- created_at: z.number().int().optional(),
- updated_at: z.number().int().optional(),
- });
- export type AmneziawgClient = z.infer<typeof AmneziawgClientSchema>;
- // Server-wide AmneziaWG 3.1 obfuscation parameters and tunnel identity,
- // mirroring internal/amneziawg.ServerSettings on the Go side exactly (same
- // field names) — the listen port is not duplicated here, it's the inbound's
- // own port like every other protocol. H1-H4 blank falls back to the classic
- // 1/2/3/4 magic header on save; blank optional fields omit their feature
- // from the rendered config.
- export const AmneziawgServerSchema = z.object({
- privateKey: z.string().optional(),
- publicKey: z.string().optional(),
- subnetIp: z.string().default('10.8.1.0'),
- subnetCidr: clearedToDefault(z.number().int().min(1).max(32).default(24)),
- mtu: optionalClearedInt(z.number().int().min(1)),
- primaryDns: z.string().default('8.8.8.8'),
- secondaryDns: z.string().default('8.8.4.4'),
- externalInterface: z.string().default(''),
- ipv6Enabled: z.boolean().default(false),
- ipv6Subnet: z.string().default(''),
- ipv6ExternalInterface: z.string().default(''),
- // routeThroughXray is vestigial on the Go side (see ServerSettings' own
- // doc comment) -- the embedded relay is always on, this field is read by
- // nothing. Kept here anyway, with no corresponding form control, purely so
- // z.object's default unknown-key stripping doesn't silently drop it from
- // an existing stored settings blob on the next save.
- routeThroughXray: z.boolean().default(false).optional(),
- // Upper bounds match amneziawg-go's own UAPI parsers (device/uapi.go):
- // jc/jmin/jmax are uint32, s1-s4 uint16. Wider values make IpcSet fail.
- jc: clearedToDefault(z.number().int().min(0).max(4294967295).default(5)),
- jmin: clearedToDefault(z.number().int().min(0).max(4294967295).default(10)),
- jmax: clearedToDefault(z.number().int().min(0).max(4294967295).default(50)),
- s1: clearedToDefault(z.number().int().min(0).max(65535).default(30)),
- s2: clearedToDefault(z.number().int().min(0).max(65535).default(45)),
- s3: clearedToDefault(z.number().int().min(0).max(64).default(10)),
- s4: clearedToDefault(z.number().int().min(0).max(32).default(5)),
- h1: z.string().default(''),
- h2: z.string().default(''),
- h3: z.string().default(''),
- h4: z.string().default(''),
- i1: z.string().default(''),
- i2: z.string().default(''),
- i3: z.string().default(''),
- i4: z.string().default(''),
- i5: z.string().default(''),
- headerProtectionKey: z.string().default(''),
- contentPaddingAddition: z.string().default(''),
- rekeyAfterTime: z.string().default(''),
- rekeyTimeout: z.string().default(''),
- rejectAfterTime: z.string().default(''),
- keepaliveTimeout: z.string().default(''),
- maxHandshakeAttempts: z.string().default(''),
- randomTrailers: z.boolean().default(false),
- disableCookies: z.boolean().default(false),
- });
- export type AmneziawgServer = z.infer<typeof AmneziawgServerSchema>;
- export const AmneziawgInboundSettingsSchema = z.object({
- server: AmneziawgServerSchema,
- clients: z.array(AmneziawgClientSchema).default([]),
- });
- export type AmneziawgInboundSettings = z.infer<typeof AmneziawgInboundSettingsSchema>;
|