import type * as http from 'node:http'; import type { JwsVerifier } from './server.classes.jws.verifier.js'; import { AcmeServerError } from './server.classes.jws.verifier.js'; import type { IServerOrderStore } from './server.interfaces.js'; import type { AcmeServerCA } from './server.classes.ca.js'; /** * POST /finalize/:id — Submit CSR and issue certificate. */ export function createFinalizeHandler( baseUrl: string, jwsVerifier: JwsVerifier, orderStore: IServerOrderStore, ca: AcmeServerCA, ) { return async ( req: http.IncomingMessage, res: http.ServerResponse, params: Record, body: any, ): Promise => { const orderId = params.id; const requestUrl = `${baseUrl}/finalize/${orderId}`; const verified = await jwsVerifier.verify(body, requestUrl); if (!verified.kid) { throw new AcmeServerError(400, 'urn:ietf:params:acme:error:malformed', 'Finalize requires kid'); } const order = await orderStore.getOrder(orderId); if (!order) { throw new AcmeServerError(404, 'urn:ietf:params:acme:error:malformed', 'Order not found'); } // Check all authorizations are valid and update order status if needed if (order.status === 'pending') { let allValid = true; for (const authzId of order.authorizationIds) { const authz = await orderStore.getAuthorization(authzId); if (!authz || authz.status !== 'valid') { allValid = false; break; } } if (allValid) { await orderStore.updateOrder(orderId, { status: 'ready' }); order.status = 'ready'; } } if (order.status !== 'ready') { throw new AcmeServerError( 403, 'urn:ietf:params:acme:error:orderNotReady', `Order is in "${order.status}" state, expected "ready"`, ); } const { payload } = verified; if (!payload?.csr) { throw new AcmeServerError(400, 'urn:ietf:params:acme:error:malformed', 'Missing CSR in finalize request'); } // Transition to processing await orderStore.updateOrder(orderId, { status: 'processing' }); // Sign the certificate const certPem = await ca.signCsr(payload.csr); // Store certificate and update order const certUrl = `${baseUrl}/cert/${orderId}`; await orderStore.storeCertPem(orderId, certPem); await orderStore.updateOrder(orderId, { status: 'valid', certificate: certUrl, }); const responseBody = { status: 'valid', expires: order.expires, identifiers: order.identifiers, authorizations: order.authorizationIds.map((id) => `${baseUrl}/authz/${id}`), finalize: order.finalize, certificate: certUrl, }; res.writeHead(200, { 'Content-Type': 'application/json', 'Location': `${baseUrl}/order/${orderId}`, }); res.end(JSON.stringify(responseBody)); }; }