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

242 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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(),
/** One native session ID matches several clients; online/address are not confirmed. */
sessionAmbiguous: z.boolean().optional(),
activeAddress: z.string().optional(),
activeSince: z.string().optional(),
disabled: z.boolean(),
comment: z.string().optional(),
/** Создан менеджером (managed-комментарий). */
managed: z.boolean(),
}).refine(c => !c.sessionAmbiguous || (!c.online && !c.activeAddress && !c.activeSince), {
message: "Неоднозначная сессия IPsec не может подтверждать online или активный адрес",
})
/** Слушатель 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(),
clientsSessionAmbiguous: z.number().int().nonnegative().optional(),
/** Все сертификаты роутера (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>