Docker images / prepare-release (push) Successful in 7s
Docker images / backend-test (push) Successful in 1m51s
Docker images / frontend-image (push) Successful in 2m19s
Docker images / updater-image (push) Successful in 39s
Docker images / backend-image (push) Successful in 2m40s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 11s
Co-authored-by: Cursor <cursoragent@cursor.com>
237 lines
9.9 KiB
TypeScript
237 lines
9.9 KiB
TypeScript
import { z } from "zod"
|
||
|
||
export const ipsecAuthMethodSchema = z.enum(["certificate", "pre-shared-key"])
|
||
|
||
/**
|
||
* Минимальная длина пароля .p12. Ограничение RouterOS REST:
|
||
* `Failure: If used, passphrase must be at least 8 chars long!` (см. /certificate/export-certificate).
|
||
*/
|
||
export const IPSEC_MIN_PASSPHRASE = 8
|
||
|
||
/** Клиент IKEv2 — /ip/ipsec/identity (+ опциональный персональный mode-config). */
|
||
export const ipsecClientDtoSchema = z.object({
|
||
id: z.string().min(1),
|
||
rosId: z.string().min(1),
|
||
serverId: z.string().min(1),
|
||
serverName: z.string(),
|
||
/** Управляемое имя клиента (из managed-комментария identity). */
|
||
name: z.string(),
|
||
authMethod: ipsecAuthMethodSchema,
|
||
/** cert — клиент по сертификату (может быть без персональной identity); psk — pre-shared-key identity. */
|
||
kind: z.enum(["cert", "psk"]).default("cert"),
|
||
certificateName: z.string().optional(),
|
||
/** Имя клиентского сертификата (роль client). Для psk — undefined. */
|
||
certName: z.string().optional(),
|
||
/** CA, которым подписан клиентский сертификат (read-only поле `ca`). */
|
||
signedBy: z.string().optional(),
|
||
commonName: z.string().optional(),
|
||
remoteId: z.string().optional(),
|
||
/** Статический IP клиента (персональный mode-config), undefined — из общего пула. */
|
||
staticIp: z.string().optional(),
|
||
modeConfigName: z.string().optional(),
|
||
peerName: z.string().optional(),
|
||
online: z.boolean(),
|
||
activeAddress: z.string().optional(),
|
||
activeSince: z.string().optional(),
|
||
disabled: z.boolean(),
|
||
comment: z.string().optional(),
|
||
/** Создан менеджером (managed-комментарий). */
|
||
managed: z.boolean(),
|
||
})
|
||
|
||
/** Слушатель IKEv2 — /ip/ipsec/peer (passive). */
|
||
export const ipsecPeerDtoSchema = z.object({
|
||
id: z.string().min(1),
|
||
rosId: z.string().min(1),
|
||
serverId: z.string().min(1),
|
||
serverName: z.string(),
|
||
name: z.string(),
|
||
address: z.string().optional(),
|
||
exchangeMode: z.string().optional(),
|
||
passive: z.boolean().optional(),
|
||
certificate: z.string().optional(),
|
||
profile: z.string().optional(),
|
||
disabled: z.boolean(),
|
||
comment: z.string().optional(),
|
||
managed: z.boolean(),
|
||
})
|
||
|
||
export const ipsecModeConfigDtoSchema = z.object({
|
||
id: z.string().min(1),
|
||
rosId: z.string().min(1),
|
||
serverId: z.string().min(1),
|
||
name: z.string(),
|
||
/** Общий пул (shared) или персональный статический адрес (per-user). */
|
||
addressPool: z.string().optional(),
|
||
address: z.string().optional(),
|
||
splitDns: z.string().optional(),
|
||
staticDns: z.string().optional(),
|
||
comment: z.string().optional(),
|
||
managed: z.boolean(),
|
||
})
|
||
|
||
export const ipsecPoolDtoSchema = z.object({
|
||
id: z.string().min(1),
|
||
rosId: z.string().min(1),
|
||
serverId: z.string().min(1),
|
||
name: z.string(),
|
||
ranges: z.string(),
|
||
comment: z.string().optional(),
|
||
managed: z.boolean(),
|
||
})
|
||
|
||
export const ipsecCertInfoDtoSchema = z.object({
|
||
name: z.string(),
|
||
commonName: z.string().optional(),
|
||
keySize: z.string().optional(),
|
||
fingerprint: z.string().optional(),
|
||
expiresAt: z.string().optional(),
|
||
trusted: z.boolean().optional(),
|
||
hasPrivateKey: z.boolean().optional(),
|
||
role: z.enum(["ca", "server", "client", "other"]).optional(),
|
||
/** Имя CA, которым серт подписан на устройстве (read-only поле `ca` RouterOS). */
|
||
signedBy: z.string().optional(),
|
||
managed: z.boolean(),
|
||
})
|
||
|
||
/** Сводка IKEv2-сервера на одном роутере. */
|
||
export const ipsecServerSummaryDtoSchema = z.object({
|
||
serverId: z.string().min(1),
|
||
serverName: z.string(),
|
||
serverCountry: z.string().optional(),
|
||
/** Managed-набор (CA + серверный серт + peer + mode-config) инициализирован. */
|
||
initialized: z.boolean(),
|
||
/** Существующий IKEv2-сервер пригоден: есть peer + CA + серверный серт. */
|
||
ike2Ready: z.boolean(),
|
||
serverEndpoint: z.string().optional(),
|
||
/** Primary managed peer (обратная совместимость); для полного списка — `peers`. */
|
||
peer: ipsecPeerDtoSchema.optional(),
|
||
/** Все peers роутера (managed + существующие). */
|
||
peers: z.array(ipsecPeerDtoSchema).default([]),
|
||
pool: ipsecPoolDtoSchema.optional(),
|
||
sharedModeConfig: ipsecModeConfigDtoSchema.optional(),
|
||
caCert: ipsecCertInfoDtoSchema.optional(),
|
||
serverCert: ipsecCertInfoDtoSchema.optional(),
|
||
natRuleManaged: z.boolean(),
|
||
clientsTotal: z.number().int().nonnegative(),
|
||
clientsOnline: z.number().int().nonnegative(),
|
||
/** Все сертификаты роутера (managed + существующие). */
|
||
certs: z.array(ipsecCertInfoDtoSchema).optional(),
|
||
})
|
||
|
||
export const ipsecPeerPatchSchema = z.object({
|
||
name: z.string().min(1).max(64).optional(),
|
||
address: z.string().optional(),
|
||
exchangeMode: z.string().optional(),
|
||
passive: z.boolean().optional(),
|
||
certificate: z.string().optional(),
|
||
profile: z.string().optional(),
|
||
disabled: z.boolean().optional(),
|
||
})
|
||
|
||
export const ipsecCertDeleteRequestSchema = z.object({
|
||
name: z.string().min(1),
|
||
})
|
||
|
||
export const ipsecListResponseSchema = z.object({
|
||
servers: z.array(ipsecServerSummaryDtoSchema),
|
||
clients: z.array(ipsecClientDtoSchema),
|
||
failures: z
|
||
.array(
|
||
z.object({
|
||
serverId: z.string(),
|
||
serverName: z.string().optional(),
|
||
error: z.string(),
|
||
}),
|
||
)
|
||
.optional(),
|
||
})
|
||
|
||
export const ipsecInitRequestSchema = z.object({
|
||
serverId: z.union([z.string(), z.number()]),
|
||
/** Домен или IP для CN/SAN серверного сертификата (к нему подключаются клиенты). */
|
||
serverEndpoint: z.string().min(1),
|
||
/** Подсеть пула клиентов; из неё pool ranges .2–.254. */
|
||
poolCidr: z.string().regex(/^[0-9a-fA-F.:/]+$/).default("10.77.0.0/24"),
|
||
dns: z.string().optional(),
|
||
caDaysValid: z.number().int().positive().default(3650),
|
||
serverDaysValid: z.number().int().positive().default(3650),
|
||
clientDaysValid: z.number().int().positive().default(1825),
|
||
/** Managed srcnat masquerade, чтобы у клиентов был интернет. */
|
||
createNatRule: z.boolean().default(true),
|
||
})
|
||
|
||
export const ipsecUserCreateRequestSchema = z.object({
|
||
serverId: z.union([z.string(), z.number()]),
|
||
/** Отображаемое имя клиента; из него slug для серта/CN. */
|
||
name: z.string().min(1).max(64),
|
||
/** Peer (сервер), к которому привязать identity; без — primary managed peer выбранного сервера. */
|
||
peerName: z.string().optional(),
|
||
authMethod: ipsecAuthMethodSchema.default("certificate"),
|
||
psk: z.string().min(8).optional(),
|
||
remoteId: z.string().optional(),
|
||
/** Конкретный IP клиента; без — выдаётся из пула. */
|
||
staticIp: z.string().optional(),
|
||
/** Пароль на экспортируемый .p12 (RouterOS требует ≥ IPSEC_MIN_PASSPHRASE). */
|
||
passphrase: z.string().min(IPSEC_MIN_PASSPHRASE).optional(),
|
||
daysValid: z.number().int().positive().optional(),
|
||
})
|
||
|
||
export const ipsecUserPatchSchema = z.object({
|
||
name: z.string().min(1).max(64).optional(),
|
||
/** null — вернуть выдачу из пула. */
|
||
staticIp: z.string().nullable().optional(),
|
||
psk: z.string().min(8).optional(),
|
||
remoteId: z.string().optional(),
|
||
disabled: z.boolean().optional(),
|
||
})
|
||
|
||
export const ipsecCertExportRequestSchema = z.object({
|
||
serverId: z.union([z.string(), z.number()]),
|
||
clientId: z.string().min(1),
|
||
passphrase: z.string().min(IPSEC_MIN_PASSPHRASE),
|
||
})
|
||
|
||
/** Экспорт .p12 существующего клиентского сертификата по имени (client1/anakondra и т.п.). */
|
||
export const ipsecCertExportByNameRequestSchema = z.object({
|
||
name: z.string().min(1),
|
||
passphrase: z.string().min(IPSEC_MIN_PASSPHRASE),
|
||
})
|
||
|
||
/** Бандл для авторизации клиента: .p12 (+ strongSwan .sswan + инструкция). */
|
||
export const ipsecCertBundleSchema = z.object({
|
||
user: z.string(),
|
||
serverEndpoint: z.string().optional(),
|
||
filename: z.string(),
|
||
contentB64: z.string(),
|
||
mime: z.string().default("application/x-pkcs12"),
|
||
passphrase: z.string().optional(),
|
||
sswanFilename: z.string().optional(),
|
||
sswanContent: z.string().optional(),
|
||
instructions: z.string().optional(),
|
||
})
|
||
|
||
export const ipsecUserCreatedSchema = z.object({
|
||
client: ipsecClientDtoSchema,
|
||
/** Одноразовый бандл сертификата (для cert-клиентов). */
|
||
bundle: ipsecCertBundleSchema.optional(),
|
||
})
|
||
|
||
export type IpsecAuthMethod = z.infer<typeof ipsecAuthMethodSchema>
|
||
export type IpsecClientDto = z.infer<typeof ipsecClientDtoSchema>
|
||
export type IpsecPeerDto = z.infer<typeof ipsecPeerDtoSchema>
|
||
export type IpsecPeerPatch = z.infer<typeof ipsecPeerPatchSchema>
|
||
export type IpsecCertDeleteRequest = z.infer<typeof ipsecCertDeleteRequestSchema>
|
||
export type IpsecModeConfigDto = z.infer<typeof ipsecModeConfigDtoSchema>
|
||
export type IpsecPoolDto = z.infer<typeof ipsecPoolDtoSchema>
|
||
export type IpsecCertInfoDto = z.infer<typeof ipsecCertInfoDtoSchema>
|
||
export type IpsecServerSummaryDto = z.infer<typeof ipsecServerSummaryDtoSchema>
|
||
export type IpsecListResponse = z.infer<typeof ipsecListResponseSchema>
|
||
export type IpsecInitRequest = z.infer<typeof ipsecInitRequestSchema>
|
||
export type IpsecUserCreateRequest = z.infer<typeof ipsecUserCreateRequestSchema>
|
||
export type IpsecUserPatch = z.infer<typeof ipsecUserPatchSchema>
|
||
export type IpsecCertExportRequest = z.infer<typeof ipsecCertExportRequestSchema>
|
||
export type IpsecCertExportByNameRequest = z.infer<typeof ipsecCertExportByNameRequestSchema>
|
||
export type IpsecCertBundle = z.infer<typeof ipsecCertBundleSchema>
|
||
export type IpsecUserCreated = z.infer<typeof ipsecUserCreatedSchema>
|