fix(ipsec): убрать неподдерживаемый параметр при подписи сертификата
Docker images / prepare-release (push) Successful in 6s
Docker images / backend-test (push) Successful in 1m37s
Docker images / frontend-image (push) Successful in 2m17s
Docker images / updater-image (push) Successful in 38s
Docker images / backend-image (push) Successful in 2m20s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 9s

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Denozordec
2026-09-12 22:21:19 +07:00
co-authored by Cursor
parent 0e1524c600
commit a3502b9755
+22 -11
View File
@@ -696,21 +696,32 @@ export class MikrotikClient {
: new Error(`Не удалось скачать файл ${normalized} с RouterOS`)
}
/** Создание ключевой пары + заявки: /certificate add (поля common-name, key-size, key-usage…). */
async addCertificate(body: Record<string, string>, timeoutMs = 30_000): Promise<unknown> {
// Набор параметров `/certificate/add` зависит от версии RouterOS (напр. `comment`).
// Деградируем: при 400 «unknown parameter X» убираем X из тела и повторяем.
/**
* POST с деградацией по несовместимым параметрам: набор полей `/certificate/*` зависит от версии
* RouterOS (напр. `comment`, `days-valid`). При 400 «unknown parameter X» убираем X и повторяем.
*/
private async postTolerant(
path: string,
body: Record<string, string>,
timeoutMs: number,
maxAttempts = 4,
): Promise<unknown> {
const payload: Record<string, string> = { ...body }
for (let attempt = 0; attempt < 4; attempt += 1) {
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
try {
return await this.post("/certificate/add", payload, timeoutMs)
return await this.post(path, payload, timeoutMs)
} catch (error) {
const param = error instanceof MikrotikError ? unknownParameterName(error) : undefined
if (!param || !(param in payload)) throw error
delete payload[param]
}
}
throw new Error(`RouterOS: не удалось добавить сертификат (несовместимые параметры): ${Object.keys(body).join(", ")}`)
throw new Error(`RouterOS: не удалось выполнить ${path} (несовместимые параметры): ${Object.keys(body).join(", ")}`)
}
/** Создание ключевой пары + заявки: /certificate add (поля common-name, key-size, key-usage…). */
async addCertificate(body: Record<string, string>, timeoutMs = 30_000): Promise<unknown> {
return this.postTolerant("/certificate/add", body, timeoutMs)
}
/** Подпись сертификата локальным CA; sign небыстрый — увеличенный таймаут. */
@@ -723,14 +734,14 @@ export class MikrotikClient {
if (params.ca) body.ca = params.ca
if (params.daysValid != null) body["days-valid"] = String(params.daysValid)
try {
return await this.post("/certificate/sign", body, timeoutMs)
return await this.postTolerant("/certificate/sign", body, timeoutMs)
} catch (e) {
// Некоторые версии REST принимают цель подписи только как .id.
const certs = await this.getCertificates()
const row = certs.find((c) => String(c.name ?? "") === params.name)
const id = row?.[".id"]
if (!id) throw e
return await this.post("/certificate/sign", { ".id": id, ...body }, timeoutMs)
return await this.postTolerant("/certificate/sign", { ".id": id, ...body }, timeoutMs)
}
}
@@ -744,12 +755,12 @@ export class MikrotikClient {
if (params.passphrase?.trim()) body["export-passphrase"] = params.passphrase.trim()
let raw: unknown
try {
raw = await this.post("/certificate/export-certificate", body, timeoutMs)
raw = await this.postTolerant("/certificate/export-certificate", body, timeoutMs)
} catch (e) {
const certs = await this.getCertificates()
const id = certs.find((c) => String(c.name ?? "") === params.name)?.[".id"]
if (!id) throw e
raw = await this.post("/certificate/export-certificate", { ".id": id, ...body }, timeoutMs)
raw = await this.postTolerant("/certificate/export-certificate", { ".id": id, ...body }, timeoutMs)
}
void raw
// RouterOS создаёт cert_export_<name>.p12 либо <name>.p12 — ищем по списку файлов.