diff --git a/backend/src/db/migrations/20251027234547_add-pki-acme.ts b/backend/src/db/migrations/20251027234547_add-pki-acme.ts index a2e1ab777..c0cf0db4f 100644 --- a/backend/src/db/migrations/20251027234547_add-pki-acme.ts +++ b/backend/src/db/migrations/20251027234547_add-pki-acme.ts @@ -54,8 +54,8 @@ export async function up(knex: Knex): Promise { // Multi-value emails array t.specificType("emails", "text[]").notNullable(); - // Public key (PEM format) - t.text("publicKey").notNullable(); + // Public key (JWK format) + t.jsonb("publicKey").notNullable(); t.timestamps(true, true, true); }); diff --git a/backend/src/db/schemas/pki-acme-accounts.ts b/backend/src/db/schemas/pki-acme-accounts.ts index 739e7057b..b599cec07 100644 --- a/backend/src/db/schemas/pki-acme-accounts.ts +++ b/backend/src/db/schemas/pki-acme-accounts.ts @@ -11,7 +11,7 @@ export const PkiAcmeAccountsSchema = z.object({ id: z.string().uuid(), profileId: z.string().uuid(), emails: z.string().array(), - publicKey: z.string(), + publicKey: z.unknown(), createdAt: z.date(), updatedAt: z.date() }); diff --git a/backend/src/ee/routes/v1/pki-acme-router.ts b/backend/src/ee/routes/v1/pki-acme-router.ts index 5f19359a6..c8ca31186 100644 --- a/backend/src/ee/routes/v1/pki-acme-router.ts +++ b/backend/src/ee/routes/v1/pki-acme-router.ts @@ -20,12 +20,14 @@ import { GetAcmeOrderSchema, ListAcmeOrdersResponseSchema, ListAcmeOrdersSchema, + RawJwsPayloadSchema, RespondToAcmeChallengeResponseSchema, RespondToAcmeChallengeSchema } from "@app/ee/services/pki-acme/pki-acme-schemas"; import { ApiDocsTags } from "@app/lib/api-docs"; import { getConfig } from "@app/lib/config/env"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; +import { TRawJwsPayload } from "@app/ee/services/pki-acme/pki-acme-types"; export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => { const appCfg = getConfig(); @@ -104,16 +106,22 @@ export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => { hide: false, tags: [ApiDocsTags.PkiAcme], description: "ACME New Account - register a new account or find existing one", - ...CreateAcmeAccountSchema.shape, + ...RawJwsPayloadSchema.shape, response: { 201: CreateAcmeAccountResponseSchema } }, handler: async (req, res) => { // TODO: check nonce here - // TODO: check signature here + const { payload, protectedHeader, jwk } = await server.services.pkiAcme.validateCreateAcmeAccountJwsPayload( + req.body as TRawJwsPayload + ); - const account = await server.services.pkiAcme.createAcmeAccount(req.params.profileId, req.body); + const account = await server.services.pkiAcme.createAcmeAccount( + req.params.profileId, + jwk, + payload as TCreateAcmeAccountPayload + ); // TODO: deal with existing account case here res.code(201); res.header(