Files
MikrotikManager/backend/src/services/certificate-issue-request.ts
T

33 lines
2.1 KiB
TypeScript

import { randomUUID } from "node:crypto"
import type { CertificateIssueRequest } from "@mmapp/contracts/certificates"
import { parseJsonArray } from "../db/json.js"
export type IssueRecordInput = { id: string; serverId: string; certName: string; domainNames: string[]; keyType: string; trustStore: string; source: "manual" }
type ExistingIssue = { serverId: number | string; certName: string; domainNames: unknown; keyType: string; trustStore: string; source: string }
export class IssueRequestError extends Error {
constructor(message: string, readonly status: number) { super(message) }
}
export async function acceptCertificateIssueRequest(input: CertificateIssueRequest, deps: {
getServer: (id: string) => Promise<unknown | null>
getJob: (id: string) => Promise<ExistingIssue | null>
createJob: (row: IssueRecordInput) => Promise<boolean>
queue: (id: string) => void
}) {
const id = input.requestId ?? randomUUID()
const row: IssueRecordInput = { id, serverId: String(input.serverId), certName: input.certName, domainNames: input.domainNames, keyType: input.keyType ?? "rsa2048", trustStore: (input.trustStore ?? ["www", "api"]).join(","), source: "manual" }
const matches = (existing: ExistingIssue) => String(existing.serverId) === row.serverId && existing.certName === row.certName && JSON.stringify(parseJsonArray(existing.domainNames)) === JSON.stringify(row.domainNames) && existing.keyType === row.keyType && existing.trustStore === row.trustStore && existing.source === "manual"
const previous = await deps.getJob(id)
if (previous) {
if (!matches(previous)) throw new IssueRequestError("requestId уже относится к другому выпуску", 409)
return { jobId: id }
}
if (!await deps.getServer(row.serverId)) throw new IssueRequestError("Сервер не найден", 404)
const created = await deps.createJob(row)
if (!created) {
const existing = await deps.getJob(id)
if (!existing || !matches(existing)) throw new IssueRequestError("requestId уже относится к другому выпуску", 409)
} else deps.queue(id)
return { jobId: id }
}