From 76505939f3389d98adb395125f9ffe4271c880a2 Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Wed, 29 Oct 2025 16:13:51 -0700 Subject: [PATCH] Add acme order table --- backend/src/@types/knex.d.ts | 5 ++++ ...acme.ts => 20251029234547_add-pki-acme.ts} | 25 +++++++++++++++++ backend/src/db/schemas/index.ts | 1 + backend/src/db/schemas/models.ts | 1 + .../src/db/schemas/pki-acme-order-auths.ts | 20 ++++++++++++++ .../pki-acme/pki-acme-order-auth-dal.ts | 27 +++++++++++++++++++ .../ee/services/pki-acme/pki-acme-service.ts | 15 +++++++++-- backend/src/server/routes/index.ts | 5 +++- 8 files changed, 96 insertions(+), 3 deletions(-) rename backend/src/db/migrations/{20251027234547_add-pki-acme.ts => 20251029234547_add-pki-acme.ts} (89%) create mode 100644 backend/src/db/schemas/pki-acme-order-auths.ts create mode 100644 backend/src/ee/services/pki-acme/pki-acme-order-auth-dal.ts diff --git a/backend/src/@types/knex.d.ts b/backend/src/@types/knex.d.ts index 8a19670f0..1daf722a1 100644 --- a/backend/src/@types/knex.d.ts +++ b/backend/src/@types/knex.d.ts @@ -728,6 +728,11 @@ declare module "knex/types/tables" { TPkiAcmeOrdersUpdate >; [TableName.PkiAcmeAuth]: KnexOriginal.CompositeTableType; + [TableName.PkiAcmeOrderAuth]: KnexOriginal.CompositeTableType< + TPkiAcmeOrderAuths, + TPkiAcmeOrderAuthsInsert, + TPkiAcmeOrderAuthsUpdate + >; [TableName.PkiAcmeChallenge]: KnexOriginal.CompositeTableType< TPkiAcmeChallenges, TPkiAcmeChallengesInsert, diff --git a/backend/src/db/migrations/20251027234547_add-pki-acme.ts b/backend/src/db/migrations/20251029234547_add-pki-acme.ts similarity index 89% rename from backend/src/db/migrations/20251027234547_add-pki-acme.ts rename to backend/src/db/migrations/20251029234547_add-pki-acme.ts index 285676c8f..6390e5812 100644 --- a/backend/src/db/migrations/20251027234547_add-pki-acme.ts +++ b/backend/src/db/migrations/20251029234547_add-pki-acme.ts @@ -116,6 +116,25 @@ export async function up(knex: Knex): Promise { await createOnUpdateTrigger(knex, TableName.PkiAcmeAuth); } + // Create PkiAcmeOrderAuth table + if (!(await knex.schema.hasTable(TableName.PkiAcmeOrderAuth))) { + await knex.schema.createTable(TableName.PkiAcmeOrderAuth, (t) => { + t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); + + // Foreign key to PkiAcmeOrder + t.uuid("orderId").notNullable(); + t.foreign("orderId").references("id").inTable(TableName.PkiAcmeOrder).onDelete("CASCADE"); + + // Foreign key to PkiAcmeAuth + t.uuid("authId").notNullable(); + t.foreign("authId").references("id").inTable(TableName.PkiAcmeAuth).onDelete("CASCADE"); + + t.timestamps(true, true, true); + }); + + await createOnUpdateTrigger(knex, TableName.PkiAcmeOrderAuth); + } + // Create PkiAcmeChallenge table if (!(await knex.schema.hasTable(TableName.PkiAcmeChallenge))) { await knex.schema.createTable(TableName.PkiAcmeChallenge, (t) => { @@ -150,6 +169,12 @@ export async function down(knex: Knex): Promise { await dropOnUpdateTrigger(knex, TableName.PkiAcmeChallenge); } + // Drop PkiAcmeOrderAuth (depends on PkiAcmeOrder and PkiAcmeAuth) + if (await knex.schema.hasTable(TableName.PkiAcmeOrderAuth)) { + await knex.schema.dropTable(TableName.PkiAcmeOrderAuth); + await dropOnUpdateTrigger(knex, TableName.PkiAcmeOrderAuth); + } + // Drop PkiAcmeAuth (depends on PkiAcmeAccount and Certificate) if (await knex.schema.hasTable(TableName.PkiAcmeAuth)) { await knex.schema.dropTable(TableName.PkiAcmeAuth); diff --git a/backend/src/db/schemas/index.ts b/backend/src/db/schemas/index.ts index 3eef75d16..e3db789ac 100644 --- a/backend/src/db/schemas/index.ts +++ b/backend/src/db/schemas/index.ts @@ -97,6 +97,7 @@ export * from "./pki-acme-auths"; export * from "./pki-acme-challenges"; export * from "./pki-acme-enrollment-configs"; export * from "./pki-acme-orders"; +export * from "./pki-acme-order-auths"; export * from "./pki-alerts"; export * from "./pki-api-enrollment-configs"; export * from "./pki-certificate-profiles"; diff --git a/backend/src/db/schemas/models.ts b/backend/src/db/schemas/models.ts index 0fcda08d7..a031c83b9 100644 --- a/backend/src/db/schemas/models.ts +++ b/backend/src/db/schemas/models.ts @@ -30,6 +30,7 @@ export enum TableName { PkiAcmeEnrollmentConfig = "pki_acme_enrollment_configs", PkiAcmeAccount = "pki_acme_accounts", PkiAcmeOrder = "pki_acme_orders", + PkiAcmeOrderAuth = "pki_acme_order_auths", PkiAcmeAuth = "pki_acme_auths", PkiAcmeChallenge = "pki_acme_challenges", PkiSubscriber = "pki_subscribers", diff --git a/backend/src/db/schemas/pki-acme-order-auths.ts b/backend/src/db/schemas/pki-acme-order-auths.ts new file mode 100644 index 000000000..66f8704f2 --- /dev/null +++ b/backend/src/db/schemas/pki-acme-order-auths.ts @@ -0,0 +1,20 @@ +// Code generated by automation script, DO NOT EDIT. +// Automated by pulling database and generating zod schema +// To update. Just run npm run generate:schema +// Written by akhilmhdh. + +import { z } from "zod"; + +import { TImmutableDBKeys } from "./models"; + +export const PkiAcmeOrderAuthsSchema = z.object({ + id: z.string().uuid(), + orderId: z.string().uuid(), + authId: z.string().uuid(), + createdAt: z.date(), + updatedAt: z.date() +}); + +export type TPkiAcmeOrderAuths = z.infer; +export type TPkiAcmeOrderAuthsInsert = Omit, TImmutableDBKeys>; +export type TPkiAcmeOrderAuthsUpdate = Partial, TImmutableDBKeys>>; diff --git a/backend/src/ee/services/pki-acme/pki-acme-order-auth-dal.ts b/backend/src/ee/services/pki-acme/pki-acme-order-auth-dal.ts new file mode 100644 index 000000000..87b6f8211 --- /dev/null +++ b/backend/src/ee/services/pki-acme/pki-acme-order-auth-dal.ts @@ -0,0 +1,27 @@ +import { Knex } from "knex"; + +import { TDbClient } from "@app/db"; +import { TableName } from "@app/db/schemas"; +import { TPkiAcmeOrderAuthsInsert } from "@app/db/schemas/pki-acme-order-auths"; +import { DatabaseError } from "@app/lib/errors"; +import { ormify } from "@app/lib/knex"; + +export type TPkiAcmeOrderAuthDALFactory = ReturnType; + +export const pkiAcmeOrderAuthDALFactory = (db: TDbClient) => { + const pkiAcmeOrderAuthOrm = ormify(db, TableName.PkiAcmeOrderAuth); + + const insertMany = async (rows: TPkiAcmeOrderAuthsInsert[], tx?: Knex) => { + try { + const result = await (tx || db)(TableName.PkiAcmeOrderAuth).insert(rows).returning("*"); + return result; + } catch (error) { + throw new DatabaseError({ error, name: "Insert many PKI ACME order auths" }); + } + }; + + return { + ...pkiAcmeOrderAuthOrm, + insertMany + }; +}; diff --git a/backend/src/ee/services/pki-acme/pki-acme-service.ts b/backend/src/ee/services/pki-acme/pki-acme-service.ts index 9e1167aec..e8967a9ac 100644 --- a/backend/src/ee/services/pki-acme/pki-acme-service.ts +++ b/backend/src/ee/services/pki-acme/pki-acme-service.ts @@ -11,6 +11,7 @@ import { } from "./pki-acme-errors"; import { TPkiAcmeAccounts } from "@app/db/schemas/pki-acme-accounts"; +import { TPkiAcmeAuths } from "@app/db/schemas/pki-acme-auths"; import { logger } from "@app/lib/logger"; import { EnrollmentType, @@ -21,6 +22,7 @@ import { z, ZodError } from "zod"; import { TPkiAcmeAccountDALFactory } from "./pki-acme-account-dal"; import { TPkiAcmeAuthDALFactory } from "./pki-acme-auth-dal"; import { TPkiAcmeOrderDALFactory } from "./pki-acme-order-dal"; +import { TPkiAcmeOrderAuthDALFactory } from "./pki-acme-order-auth-dal"; import { AcmeAuthStatus, AcmeIdentifierType, @@ -54,13 +56,15 @@ type TPkiAcmeServiceFactoryDep = { acmeAccountDAL: Pick; acmeOrderDAL: Pick; acmeAuthDAL: Pick; + acmeOrderAuthDAL: Pick; }; export const pkiAcmeServiceFactory = ({ certificateProfileDAL, acmeAccountDAL, acmeOrderDAL, - acmeAuthDAL + acmeAuthDAL, + acmeOrderAuthDAL }: TPkiAcmeServiceFactoryDep): TPkiAcmeServiceFactory => { const validateAcmeProfile = async (profileId: string): Promise => { const profile = await certificateProfileDAL.findById(profileId); @@ -260,7 +264,7 @@ export const pkiAcmeServiceFactory = ({ accountId: account.id, status: AcmeOrderStatus.Pending }); - const authorizations = await Promise.all( + const authorizations: TPkiAcmeAuths[] = await Promise.all( payload.identifiers.map(async (identifier) => { if (identifier.type === AcmeIdentifierType.DNS) { // TODO: reuse existing authorizations for this identifier if they exist @@ -278,6 +282,13 @@ export const pkiAcmeServiceFactory = ({ }) ); + await acmeOrderAuthDAL.insertMany( + authorizations.map((auth) => ({ + orderId: order.id, + authId: auth.id + })) + ); + // FIXME: Implement ACME new order creation const orderId = "FIXME-order-id"; return { diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 376baaaae..40ffe4f5d 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -76,6 +76,7 @@ import { permissionServiceFactory } from "@app/ee/services/permission/permission import { pitServiceFactory } from "@app/ee/services/pit/pit-service"; import { pkiAcmeAuthDALFactory } from "@app/ee/services/pki-acme/pki-acme-auth-dal"; import { pkiAcmeServiceFactory } from "@app/ee/services/pki-acme/pki-acme-service"; +import { pkiAcmeOrderAuthDALFactory } from "@app/ee/services/pki-acme/pki-acme-order-auth-dal"; import { projectTemplateDALFactory } from "@app/ee/services/project-template/project-template-dal"; import { projectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-service"; import { rateLimitDALFactory } from "@app/ee/services/rate-limit/rate-limit-dal"; @@ -1070,6 +1071,7 @@ export const registerRoutes = async ( const acmeAccountDAL = pkiAcmeAccountDALFactory(db); const acmeOrderDAL = pkiAcmeOrderDALFactory(db); const acmeAuthDAL = pkiAcmeAuthDALFactory(db); + const acmeOrderAuthDAL = pkiAcmeOrderAuthDALFactory(db); const certificateDAL = certificateDALFactory(db); const certificateBodyDAL = certificateBodyDALFactory(db); const certificateSecretDAL = certificateSecretDALFactory(db); @@ -1174,7 +1176,8 @@ export const registerRoutes = async ( certificateProfileDAL, acmeAccountDAL, acmeOrderDAL, - acmeAuthDAL + acmeAuthDAL, + acmeOrderAuthDAL }); const pkiAlertService = pkiAlertServiceFactory({