This commit is contained in:
Fang-Pen Lin
2025-11-07 09:18:20 -08:00
parent 9c748bf0ee
commit ac82e8071d
2 changed files with 44 additions and 15 deletions
@@ -16,11 +16,11 @@ import {
EnrollmentType, EnrollmentType,
TCertificateProfileWithConfigs TCertificateProfileWithConfigs
} from "@app/services/certificate-profile/certificate-profile-types"; } from "@app/services/certificate-profile/certificate-profile-types";
import { errors, flattenedVerify, FlattenedVerifyResult, importJWK, JWK, JWSHeaderParameters } from "jose"; import { errors, flattenedVerify, FlattenedVerifyResult, importJWK, JWSHeaderParameters } from "jose";
import { z, ZodError } from "zod"; import { z, ZodError } from "zod";
import { TPkiAcmeAccountDALFactory } from "./pki-acme-account-dal"; import { TPkiAcmeAccountDALFactory } from "./pki-acme-account-dal";
import { TPkiAcmeOrderDALFactory } from "./pki-acme-order-dal"; import { TPkiAcmeOrderDALFactory } from "./pki-acme-order-dal";
import { ProtectedHeaderSchema } from "./pki-acme-schemas"; import { CreateAcmeAccountBodySchema, ProtectedHeaderSchema } from "./pki-acme-schemas";
import { import {
TAcmeResponse, TAcmeResponse,
TCreateAcmeAccountPayload, TCreateAcmeAccountPayload,
@@ -49,7 +49,8 @@ type TPkiAcmeServiceFactoryDep = {
export const pkiAcmeServiceFactory = ({ export const pkiAcmeServiceFactory = ({
certificateProfileDAL, certificateProfileDAL,
acmeAccountDAL acmeAccountDAL,
acmeOrderDAL
}: TPkiAcmeServiceFactoryDep): TPkiAcmeServiceFactory => { }: TPkiAcmeServiceFactoryDep): TPkiAcmeServiceFactory => {
const validateAcmeProfile = async (profileId: string): Promise<TCertificateProfileWithConfigs> => { const validateAcmeProfile = async (profileId: string): Promise<TCertificateProfileWithConfigs> => {
const profile = await certificateProfileDAL.findById(profileId); const profile = await certificateProfileDAL.findById(profileId);
@@ -112,6 +113,21 @@ export const pkiAcmeServiceFactory = ({
} }
}; };
const validateNewAccountJwsPayload = async (
rawJwsPayload: TRawJwsPayload
): Promise<TJwsPayload<TCreateAcmeAccountPayload>> => {
return await validateJwsPayload(
rawJwsPayload,
async (protectedHeader) => {
if (!protectedHeader.jwk) {
throw new AcmeBadPublicKeyError({ detail: "JWK is required in the protected header" });
}
return protectedHeader.jwk as unknown as JsonWebKey;
},
CreateAcmeAccountBodySchema
);
};
const getAcmeDirectory = async (profileId: string): Promise<TGetAcmeDirectoryResponse> => { const getAcmeDirectory = async (profileId: string): Promise<TGetAcmeDirectoryResponse> => {
await validateAcmeProfile(profileId); await validateAcmeProfile(profileId);
return { return {
@@ -128,12 +144,17 @@ export const pkiAcmeServiceFactory = ({
return "FIXME-generate-nonce"; return "FIXME-generate-nonce";
}; };
const createAcmeAccount = async ( const createAcmeAccount = async ({
profileId: string, profileId,
alg: string, alg,
jwk: JWK, jwk,
{ onlyReturnExisting, contact }: TCreateAcmeAccountPayload payload: { onlyReturnExisting, contact }
): Promise<TAcmeResponse<TCreateAcmeAccountResponse>> => { }: {
profileId: string;
alg: string;
jwk: JsonWebKey;
payload: TCreateAcmeAccountPayload;
}): Promise<TAcmeResponse<TCreateAcmeAccountResponse>> => {
const profile = await validateAcmeProfile(profileId); const profile = await validateAcmeProfile(profileId);
const existingAccount: TPkiAcmeAccounts | null = await acmeAccountDAL.findByPublicKey(profileId, alg, jwk); const existingAccount: TPkiAcmeAccounts | null = await acmeAccountDAL.findByPublicKey(profileId, alg, jwk);
if (onlyReturnExisting && !existingAccount) { if (onlyReturnExisting && !existingAccount) {
@@ -176,6 +197,7 @@ export const pkiAcmeServiceFactory = ({
const createAcmeOrder = async ( const createAcmeOrder = async (
profileId: string, profileId: string,
account: TPkiAcmeAccounts,
payload: TCreateAcmeOrderPayload payload: TCreateAcmeOrderPayload
): Promise<TAcmeResponse<TCreateAcmeOrderResponse>> => { ): Promise<TAcmeResponse<TCreateAcmeOrderResponse>> => {
const profile = await validateAcmeProfile(profileId); const profile = await validateAcmeProfile(profileId);
@@ -292,6 +314,7 @@ export const pkiAcmeServiceFactory = ({
return { return {
validateJwsPayload, validateJwsPayload,
validateNewAccountJwsPayload,
getAcmeDirectory, getAcmeDirectory,
getAcmeNewNonce, getAcmeNewNonce,
createAcmeAccount, createAcmeAccount,
@@ -54,14 +54,20 @@ export type TPkiAcmeServiceFactory = {
getJWK: (protectedHeader: JWSHeaderParameters) => Promise<JsonWebKey>, getJWK: (protectedHeader: JWSHeaderParameters) => Promise<JsonWebKey>,
schema: z.ZodSchema<T> schema: z.ZodSchema<T>
) => Promise<TJwsPayload<T>>; ) => Promise<TJwsPayload<T>>;
validateNewAccountJwsPayload: (rawJwsPayload: TRawJwsPayload) => Promise<TJwsPayload<TCreateAcmeAccountPayload>>;
getAcmeDirectory: (profileId: string) => Promise<TGetAcmeDirectoryResponse>; getAcmeDirectory: (profileId: string) => Promise<TGetAcmeDirectoryResponse>;
getAcmeNewNonce: (profileId: string) => Promise<string>; getAcmeNewNonce: (profileId: string) => Promise<string>;
createAcmeAccount: ( createAcmeAccount: ({
profileId: string, profileId,
alg: string, alg,
jwk: JsonWebKey, jwk,
body: TCreateAcmeAccountPayload payload
) => Promise<TAcmeResponse<TCreateAcmeAccountResponse>>; }: {
profileId: string;
alg: string;
jwk: JsonWebKey;
payload: TCreateAcmeAccountPayload;
}) => Promise<TAcmeResponse<TCreateAcmeAccountResponse>>;
createAcmeOrder: ( createAcmeOrder: (
profileId: string, profileId: string,
body: TCreateAcmeOrderPayload body: TCreateAcmeOrderPayload