From 07cfb6dd54f78fb5c8e07e7a0593d9bb266df268 Mon Sep 17 00:00:00 2001 From: Fang-Pen Lin Date: Mon, 10 Nov 2025 17:27:50 -0800 Subject: [PATCH] Check license when creating profile --- backend/src/server/routes/index.ts | 1 + .../certificate-profile-service.ts | 23 ++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 2d4537dd0..2bb6d0c2e 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -1185,6 +1185,7 @@ export const registerRoutes = async ( certificateAuthorityCertDAL, permissionService, kmsService, + licenseService, projectDAL }); diff --git a/backend/src/services/certificate-profile/certificate-profile-service.ts b/backend/src/services/certificate-profile/certificate-profile-service.ts index 66a23a0e7..f629c817b 100644 --- a/backend/src/services/certificate-profile/certificate-profile-service.ts +++ b/backend/src/services/certificate-profile/certificate-profile-service.ts @@ -14,13 +14,14 @@ import { getConfig } from "@app/lib/config/env"; import { crypto } from "@app/lib/crypto/cryptography"; import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; +import { TLicenseServiceFactory } from "@app/ee/services/license/license-service"; import { ActorAuthMethod, ActorType } from "../auth/auth-type"; -import { TCertificateBodyDALFactory } from "../certificate/certificate-body-dal"; -import { getCertificateCredentials, isCertChainValid } from "../certificate/certificate-fns"; -import { TCertificateSecretDALFactory } from "../certificate/certificate-secret-dal"; import { TCertificateAuthorityCertDALFactory } from "../certificate-authority/certificate-authority-cert-dal"; import { TCertificateAuthorityDALFactory } from "../certificate-authority/certificate-authority-dal"; import { TCertificateTemplateV2DALFactory } from "../certificate-template-v2/certificate-template-v2-dal"; +import { TCertificateBodyDALFactory } from "../certificate/certificate-body-dal"; +import { getCertificateCredentials, isCertChainValid } from "../certificate/certificate-fns"; +import { TCertificateSecretDALFactory } from "../certificate/certificate-secret-dal"; import { TAcmeEnrollmentConfigDALFactory } from "../enrollment-config/acme-enrollment-config-dal"; import { TApiEnrollmentConfigDALFactory } from "../enrollment-config/api-enrollment-config-dal"; import { TAcmeConfigData, TApiConfigData, TEstConfigData } from "../enrollment-config/enrollment-config-types"; @@ -153,6 +154,7 @@ type TCertificateProfileServiceFactoryDep = { certificateAuthorityCertDAL: Pick; permissionService: Pick; kmsService: Pick; + licenseService: Pick; projectDAL: Pick; }; @@ -175,6 +177,7 @@ export const certificateProfileServiceFactory = ({ certificateSecretDAL, permissionService, kmsService, + licenseService, projectDAL }: TCertificateProfileServiceFactoryDep) => { const createProfile = async ({ @@ -237,6 +240,20 @@ export const certificateProfileServiceFactory = ({ message: "API enrollment requires API configuration" }); } + if (data.enrollmentType === EnrollmentType.ACME) { + const orgLicensePlan = await licenseService.getPlan(actorOrgId); + if (!orgLicensePlan.pkiAcme) { + throw new BadRequestError({ + message: + "Failed to create certificate profile due to plan restriction. Upgrade plan to create ACME certificate profile." + }); + } + if (!data.acmeConfig) { + throw new ForbiddenRequestError({ + message: "ACME enrollment requires ACME configuration" + }); + } + } // TODO: acme type currently doesn't require config obj, but add a check in the future if // we have options