Files
MikrotikManager/packages/contracts/src/wireguard.ts
T

183 lines
6.5 KiB
TypeScript

import { z } from "zod"
/** The client's remote endpoint belongs to the exporting interface, not its peer. */
export function resolveWgClientEndpoint(clientEndpoint: string | undefined, serverHost: string | undefined, listenPort: number): string | undefined {
const value = clientEndpoint?.trim() || serverHost?.trim()
if (!value || /[\s/]/.test(value) || !Number.isInteger(listenPort) || listenPort < 1 || listenPort > 65535) return undefined
const explicit = value.match(/^(\[[^\]]+\]|[^:]+):(\d+)$/)
if (explicit) return Number(explicit[2]) >= 1 && Number(explicit[2]) <= 65535 ? value : undefined
if (value.startsWith("[")) return value.endsWith("]") ? `${value}:${listenPort}` : undefined
if (value.includes(":")) return value.split(":").length > 2 && /^[\da-f:]+$/i.test(value) ? `[${value}]:${listenPort}` : undefined
return `${value}:${listenPort}`
}
export const wgStatusSchema = z.enum(["up", "down"])
export const wgPeerDtoSchema = z.object({
id: z.string().min(1),
rosId: z.string().min(1),
publicKey: z.string(),
allowedIps: z.array(z.string()),
endpoint: z.string().optional(),
latestHandshake: z.string().optional(),
transferRx: z.number().nonnegative().optional(),
transferTx: z.number().nonnegative().optional(),
persistentKeepalive: z.number().int().nonnegative().optional(),
persistent: z.boolean().optional(),
comment: z.string().optional(),
disabled: z.boolean().optional(),
name: z.string().optional(),
clientAddress: z.string().optional(),
clientDns: z.string().optional(),
clientEndpoint: z.string().optional(),
})
export const wgIfaceDtoSchema = z.object({
id: z.string().min(1),
rosId: z.string().min(1),
name: z.string().min(1),
serverId: z.string().min(1),
serverName: z.string(),
serverCountry: z.string().optional(),
listenPort: z.number().int().positive(),
mtu: z.number().int().positive(),
publicKey: z.string().optional(),
privateKey: z.string().optional(),
address: z.string().optional(),
peers: z.array(wgPeerDtoSchema),
comment: z.string(),
enabled: z.boolean(),
status: wgStatusSchema,
})
export const wgListResponseSchema = z.object({
interfaces: z.array(wgIfaceDtoSchema),
failures: z
.array(
z.object({
serverId: z.string(),
serverName: z.string().optional(),
error: z.string(),
}),
)
.optional(),
})
export const wgCreatePeerSchema = z.object({
publicKey: z.string().min(1),
allowedAddresses: z.array(z.string().min(1)).min(1),
endpointAddress: z.string().optional(),
endpointPort: z.number().int().positive().optional(),
persistentKeepalive: z.number().int().nonnegative().optional(),
comment: z.string().optional(),
name: z.string().optional(),
privateKey: z.enum(["auto", "none"]).or(z.string().min(1)).optional(),
clientAddress: z.string().optional(),
clientDns: z.string().optional(),
clientEndpoint: z.string().optional(),
disabled: z.boolean().optional(),
})
export const wgCreateInterfaceSchema = z.object({
serverId: z.union([z.string(), z.number()]),
name: z.string().min(1).max(64),
listenPort: z.number().int().positive().default(13231),
mtu: z.number().int().positive().default(1420),
comment: z.string().optional(),
privateKey: z.string().min(1).optional(),
address: z.string().optional(),
disabled: z.boolean().optional(),
peer: wgCreatePeerSchema.optional(),
})
export const wgPatchInterfaceSchema = z.object({
name: z.string().min(1).max(64).optional(),
listenPort: z.number().int().positive().optional(),
mtu: z.number().int().positive().optional(),
comment: z.string().optional(),
disabled: z.boolean().optional(),
privateKey: z.string().min(1).optional(),
})
export const wgCreatePeerRequestSchema = wgCreatePeerSchema.extend({
serverId: z.union([z.string(), z.number()]),
interfaceName: z.string().min(1),
})
export const wgPatchPeerSchema = z.object({
publicKey: z.string().min(1).optional(),
allowedAddresses: z.array(z.string().min(1)).min(1).optional(),
endpointAddress: z.string().optional(),
endpointPort: z.number().int().positive().optional(),
persistentKeepalive: z.number().int().nonnegative().optional(),
comment: z.string().optional(),
name: z.string().optional(),
disabled: z.boolean().optional(),
clientAddress: z.string().optional(),
clientDns: z.string().optional(),
clientEndpoint: z.string().optional(),
})
export const wgImportFormatSchema = z.enum(["auto", "rsc", "conf"])
export const wgImportRequestSchema = z.object({
serverId: z.union([z.string(), z.number()]),
content: z.string().min(1),
format: wgImportFormatSchema.optional().default("auto"),
dryRun: z.boolean().optional().default(false),
})
export const wgExportFormatSchema = z.enum(["rsc", "conf", "peer-conf"])
export const wgExportRequestSchema = z.object({
serverId: z.union([z.string(), z.number()]),
interfaceName: z.string().min(1),
format: wgExportFormatSchema,
peerId: z.string().optional(),
includePrivateKey: z.boolean().optional().default(false),
})
export const wgImportPreviewSchema = z.object({
format: z.enum(["rsc", "conf"]),
interface: z.object({
name: z.string(),
listenPort: z.number().int().positive().optional(),
mtu: z.number().int().positive().optional(),
privateKey: z.string().optional(),
comment: z.string().optional(),
address: z.string().optional(),
disabled: z.boolean().optional(),
}),
peers: z.array(wgCreatePeerSchema),
})
export const wgImportResponseSchema = z.object({
dryRun: z.boolean(),
preview: wgImportPreviewSchema,
applied: z
.object({
interfaceName: z.string(),
peersCreated: z.number().int().nonnegative(),
})
.optional(),
})
export const wgExportResponseSchema = z.object({
format: wgExportFormatSchema,
filename: z.string(),
content: z.string(),
})
export type WgPeerDto = z.infer<typeof wgPeerDtoSchema>
export type WgIfaceDto = z.infer<typeof wgIfaceDtoSchema>
export type WgListResponse = z.infer<typeof wgListResponseSchema>
export type WgCreateInterface = z.infer<typeof wgCreateInterfaceSchema>
export type WgPatchInterface = z.infer<typeof wgPatchInterfaceSchema>
export type WgCreatePeerRequest = z.infer<typeof wgCreatePeerRequestSchema>
export type WgPatchPeer = z.infer<typeof wgPatchPeerSchema>
export type WgImportRequest = z.infer<typeof wgImportRequestSchema>
export type WgExportRequest = z.infer<typeof wgExportRequestSchema>
export type WgImportPreview = z.infer<typeof wgImportPreviewSchema>
export type WgImportResponse = z.infer<typeof wgImportResponseSchema>
export type WgExportResponse = z.infer<typeof wgExportResponseSchema>