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 9e9fce099..d95f1f11a 100644 --- a/backend/src/ee/services/pki-acme/pki-acme-service.ts +++ b/backend/src/ee/services/pki-acme/pki-acme-service.ts @@ -3,6 +3,10 @@ import { NotFoundError } from "@app/lib/errors"; import { TCertificateProfileDALFactory } from "@app/services/certificate-profile/certificate-profile-dal"; +import { + EnrollmentType, + TCertificateProfileWithConfigs +} from "@app/services/certificate-profile/certificate-profile-types"; import { TCreateAcmeAccountPayload, TCreateAcmeAccountResponse, @@ -10,7 +14,6 @@ import { TCreateAcmeOrderResponse, TDeactivateAcmeAccountPayload, TDeactivateAcmeAccountResponse, - TDownloadAcmeCertificateDTO, TFinalizeAcmeOrderPayload, TFinalizeAcmeOrderResponse, TGetAcmeAuthorizationResponse, @@ -28,26 +31,39 @@ type TPkiAcmeServiceFactoryDep = { export const pkiAcmeServiceFactory = ({ certificateProfileDAL }: TPkiAcmeServiceFactoryDep): TPkiAcmeServiceFactory => { const appCfg = getConfig(); + const validateAcmeProfile = async (profileId: string): Promise => { + const profile = await certificateProfileDAL.findById(profileId); + if (!profile) { + throw new NotFoundError({ message: "Certificate profile not found" }); + } + if (profile.enrollmentType !== EnrollmentType.ACME) { + throw new NotFoundError({ message: "Certificate profile is not configured for ACME enrollment" }); + } + return profile; + }; + + const buildUrl = (path: string): string => { + const baseUrl = appCfg.SITE_URL ?? ""; + return `${baseUrl}${path}`; + }; + const getAcmeDirectory = async (profileId: string): Promise => { // FIXME: Implement ACME directory endpoint // Validate profile exists and is for ACME enrollment - // const profile = await certificateProfileDAL.findById(profileId); - // if (!profile) { - // throw new NotFoundError({ message: "Certificate profile not found" }); - // } + const profile = await validateAcmeProfile(profileId); // FIXME: Validate profile is configured for ACME enrollment // Return absolute URLs using SITE_URL - const baseUrl = appCfg.SITE_URL ?? ""; return { - newNonce: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/new-nonce`, - newAccount: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/new-account`, - newOrder: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/new-order` + newNonce: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/new-nonce`), + newAccount: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/new-account`), + newOrder: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/new-order`) }; }; const getAcmeNewNonce = async (profileId: string): Promise => { + const profile = await validateAcmeProfile(profileId); // FIXME: Implement ACME new nonce generation // Generate a new nonce, store it, and return it return "FIXME-generate-nonce"; @@ -57,16 +73,16 @@ export const pkiAcmeServiceFactory = ({ certificateProfileDAL }: TPkiAcmeService profileId: string, body: TCreateAcmeAccountPayload ): Promise => { + const profile = await validateAcmeProfile(profileId); // FIXME: Implement ACME new account registration // Use EAB authentication to find corresponding Infisical machine identity // Check permissions and return account information - const baseUrl = appCfg.SITE_URL || ""; const accountId = "FIXME-account-id"; return { status: "valid", - accountUrl: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/accounts/${accountId}`, + accountUrl: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/accounts/${accountId}`), contact: [], - orders: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/accounts/${accountId}/orders` + orders: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/accounts/${accountId}/orders`) }; }; @@ -74,15 +90,15 @@ export const pkiAcmeServiceFactory = ({ certificateProfileDAL }: TPkiAcmeService profileId: string, body: TCreateAcmeOrderPayload ): Promise => { + const profile = await validateAcmeProfile(profileId); // FIXME: Implement ACME new order creation const orderId = "FIXME-order-id"; - const baseUrl = appCfg.SITE_URL || ""; return { status: "pending", expires: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), identifiers: [], authorizations: [], - finalize: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/orders/${orderId}/finalize` + finalize: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/orders/${orderId}/finalize`) }; }; @@ -91,6 +107,7 @@ export const pkiAcmeServiceFactory = ({ certificateProfileDAL }: TPkiAcmeService accountId: string, body?: TDeactivateAcmeAccountPayload ): Promise => { + const profile = await validateAcmeProfile(profileId); // FIXME: Implement ACME account deactivation return { status: "deactivated" @@ -98,6 +115,7 @@ export const pkiAcmeServiceFactory = ({ certificateProfileDAL }: TPkiAcmeService }; const listAcmeOrders = async (profileId: string, accountId: string): Promise => { + const profile = await validateAcmeProfile(profileId); // FIXME: Implement ACME list orders return { orders: [] @@ -105,14 +123,14 @@ export const pkiAcmeServiceFactory = ({ certificateProfileDAL }: TPkiAcmeService }; const getAcmeOrder = async (profileId: string, orderId: string): Promise => { + const profile = await validateAcmeProfile(profileId); // FIXME: Implement ACME get order - const baseUrl = appCfg.SITE_URL || ""; return { status: "pending", expires: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), identifiers: [], authorizations: [], - finalize: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/orders/${orderId}/finalize` + finalize: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/orders/${orderId}/finalize`) }; }; @@ -121,28 +139,29 @@ export const pkiAcmeServiceFactory = ({ certificateProfileDAL }: TPkiAcmeService orderId: string, body: TFinalizeAcmeOrderPayload ): Promise => { + const profile = await validateAcmeProfile(profileId); const { csr } = body; // FIXME: Implement ACME finalize order - const baseUrl = appCfg.SITE_URL || ""; return { status: "processing", expires: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), identifiers: [], authorizations: [], - finalize: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/orders/${orderId}/finalize`, - certificate: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/orders/${orderId}/certificate` + finalize: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/orders/${orderId}/finalize`), + certificate: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/orders/${orderId}/certificate`) }; }; const downloadAcmeCertificate = async (profileId: string, orderId: string): Promise => { + const profile = await validateAcmeProfile(profileId); // FIXME: Implement ACME certificate download // Return the certificate in PEM format return "FIXME-certificate-pem"; }; const getAcmeAuthorization = async (profileId: string, authzId: string): Promise => { + const profile = await validateAcmeProfile(profileId); // FIXME: Implement ACME authorization retrieval - const baseUrl = appCfg.SITE_URL || ""; return { status: "pending", expires: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), @@ -153,7 +172,7 @@ export const pkiAcmeServiceFactory = ({ certificateProfileDAL }: TPkiAcmeService challenges: [ { type: "http-01", - url: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/authorizations/${authzId}/challenges/http-01`, + url: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/authorizations/${authzId}/challenges/http-01`), status: "pending", token: "FIXME-challenge-token" } @@ -165,12 +184,12 @@ export const pkiAcmeServiceFactory = ({ certificateProfileDAL }: TPkiAcmeService profileId: string, authzId: string ): Promise => { + const profile = await validateAcmeProfile(profileId); // FIXME: Implement ACME challenge response // Trigger verification process - const baseUrl = appCfg.SITE_URL || ""; return { type: "http-01", - url: `${baseUrl}/api/v1/pki/acme/profiles/${profileId}/authorizations/${authzId}/challenges/http-01`, + url: buildUrl(`/api/v1/pki/acme/profiles/${profileId}/authorizations/${authzId}/challenges/http-01`), status: "pending", token: "FIXME-challenge-token" };