fix(backend): улучшить обработку сертификатов и добавить поддержку цепочек сертификатов

This commit is contained in:
Denozordec
2026-05-12 20:43:34 +07:00
parent b51d979a1c
commit 1a47905beb
2 changed files with 27 additions and 13 deletions
+25 -2
View File
@@ -228,6 +228,12 @@ async function ensureAcmeAccount(client: acme.Client): Promise<void> {
}
}
function splitPemCertificates(pem: string): string[] {
return [...pem.matchAll(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g)]
.map((match) => match[0].trim())
.filter(Boolean)
}
export async function issueCertificateWithCloudflareDns(params: {
server: Server
certName: string
@@ -300,9 +306,12 @@ export async function issueCertificateWithCloudflareDns(params: {
params.onStep?.("import")
const safeBase = params.certName.replace(/[^a-zA-Z0-9._-]+/g, "_")
const chain = splitPemCertificates(certPem)
const leafPem = chain[0] ?? certPem
const chainRest = chain.slice(1)
const certFile = `${safeBase}.crt`
const keyFile = `${safeBase}.key`
const certRouterFile = await clientRos.uploadTextFile(certFile, certPem)
const certRouterFile = await clientRos.uploadTextFile(certFile, leafPem)
const keyRouterFile = await clientRos.uploadTextFile(keyFile, privateKey.toString("utf8"))
await clientRos.importCertificate({
fileName: certRouterFile,
@@ -316,7 +325,21 @@ export async function issueCertificateWithCloudflareDns(params: {
trusted: true,
trustStore: trustStoreCsv,
})
await clientRos.applyCertificateToServices(params.certName, effectiveTrustStores)
for (let index = 0; index < chainRest.length; index += 1) {
const isRoot = index === chainRest.length - 1
const caName = isRoot ? `root_${params.certName}` : `root_${params.certName}_${index + 1}`
const caFile = `${safeBase}_ca_${index + 1}.crt`
const caRouterFile = await clientRos.uploadTextFile(caFile, chainRest[index]!)
await clientRos.importCertificate({
fileName: caRouterFile,
name: caName,
trusted: true,
trustStore: trustStoreCsv,
})
}
await clientRos.applyCertificateToServices(params.certName)
} finally {
params.onStep?.("cleanup")
for (const item of txtCleanups) {
+2 -11
View File
@@ -571,21 +571,12 @@ export class MikrotikClient {
return this.post("/certificate/import", body, 60_000)
}
async applyCertificateToServices(
certName: string,
trustStores: string[] = ["www", "api"],
): Promise<void> {
const stores = trustStores.length > 0 ? trustStores : ["www", "api"]
const targets: string[] = []
if (stores.includes("www")) targets.push("www-ssl")
if (stores.includes("api")) targets.push("api-ssl")
if (targets.length === 0) targets.push("www-ssl")
async applyCertificateToServices(certName: string): Promise<void> {
const body = {
disabled: "no",
certificate: certName,
}
for (const serviceName of targets) {
for (const serviceName of ["www-ssl", "api-ssl"]) {
await this.patchIpService(serviceName, body)
}
}