From 97f5c33aea3172b8555f44e8f65b367e1188ce27 Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Fri, 16 Aug 2024 19:40:23 +0800 Subject: [PATCH] feat: added collection selection for cert template --- ...20240815045235_add-certificate-template.ts | 2 + .../src/db/schemas/certificate-templates.ts | 1 + .../server/routes/v1/certificate-router.ts | 2 + .../routes/v1/certificate-template-router.ts | 3 + .../certificate-authority-service.ts | 16 ++- .../certificate-template-service.ts | 4 + .../certificate-template-types.ts | 2 + .../hooks/api/certificateTemplates/types.ts | 3 + .../components/CertificateModal.tsx | 105 +++++++++--------- .../components/CertificateTemplateModal.tsx | 35 ++++++ .../components/CertificateTemplatesTable.tsx | 2 +- 11 files changed, 116 insertions(+), 59 deletions(-) diff --git a/backend/src/db/migrations/20240815045235_add-certificate-template.ts b/backend/src/db/migrations/20240815045235_add-certificate-template.ts index efe0daae3..9fbb606e2 100644 --- a/backend/src/db/migrations/20240815045235_add-certificate-template.ts +++ b/backend/src/db/migrations/20240815045235_add-certificate-template.ts @@ -10,6 +10,8 @@ export async function up(knex: Knex): Promise { tb.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); tb.uuid("caId").notNullable(); tb.foreign("caId").references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE"); + tb.uuid("pkiCollectionId"); + tb.foreign("pkiCollectionId").references("id").inTable(TableName.PkiCollection).onDelete("SET NULL"); tb.string("name").notNullable(); tb.string("commonName").notNullable(); tb.string("subjectAlternativeName").notNullable(); diff --git a/backend/src/db/schemas/certificate-templates.ts b/backend/src/db/schemas/certificate-templates.ts index d969d95fb..6e1989195 100644 --- a/backend/src/db/schemas/certificate-templates.ts +++ b/backend/src/db/schemas/certificate-templates.ts @@ -10,6 +10,7 @@ import { TImmutableDBKeys } from "./models"; export const CertificateTemplatesSchema = z.object({ id: z.string().uuid(), caId: z.string().uuid(), + pkiCollectionId: z.string().uuid().nullable().optional(), name: z.string(), commonName: z.string(), subjectAlternativeName: z.string(), diff --git a/backend/src/server/routes/v1/certificate-router.ts b/backend/src/server/routes/v1/certificate-router.ts index 989e79448..c492e0667 100644 --- a/backend/src/server/routes/v1/certificate-router.ts +++ b/backend/src/server/routes/v1/certificate-router.ts @@ -77,6 +77,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => { .trim() .optional() .describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.certificateTemplateId), + pkiCollectionId: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.pkiCollectionId), friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.friendlyName), commonName: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.commonName), altNames: validateAltNamesField.describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.altNames), @@ -166,6 +167,7 @@ export const registerCertRouter = async (server: FastifyZodProvider) => { .trim() .optional() .describe(CERTIFICATE_AUTHORITIES.ISSUE_CERT.certificateTemplateId), + pkiCollectionId: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.pkiCollectionId), csr: z.string().trim().min(1).describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.csr), friendlyName: z.string().trim().optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.friendlyName), commonName: z.string().trim().min(1).optional().describe(CERTIFICATE_AUTHORITIES.SIGN_CERT.commonName), diff --git a/backend/src/server/routes/v1/certificate-template-router.ts b/backend/src/server/routes/v1/certificate-template-router.ts index 90eab4521..8a3bdd523 100644 --- a/backend/src/server/routes/v1/certificate-template-router.ts +++ b/backend/src/server/routes/v1/certificate-template-router.ts @@ -13,6 +13,7 @@ const sanitizedCertificateTemplate = CertificateTemplatesSchema.pick({ name: true, commonName: true, subjectAlternativeName: true, + pkiCollectionId: true, ttl: true }); @@ -61,6 +62,7 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid schema: { body: z.object({ caId: z.string(), + pkiCollectionId: z.string().optional(), name: z.string().min(1), commonName: validateTemplateRegexField, subjectAlternativeName: validateTemplateRegexField, @@ -95,6 +97,7 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid schema: { body: z.object({ caId: z.string().optional(), + pkiCollectionId: z.string().optional(), name: z.string().min(1).optional(), commonName: validateTemplateRegexField.optional(), subjectAlternativeName: validateTemplateRegexField.optional(), diff --git a/backend/src/services/certificate-authority/certificate-authority-service.ts b/backend/src/services/certificate-authority/certificate-authority-service.ts index dd122ef9c..223403208 100644 --- a/backend/src/services/certificate-authority/certificate-authority-service.ts +++ b/backend/src/services/certificate-authority/certificate-authority-service.ts @@ -1033,6 +1033,7 @@ export const certificateAuthorityServiceFactory = ({ }: TIssueCertFromCaDTO) => { let ca: TCertificateAuthorities | undefined; let certificateTemplate: TCertificateTemplates | undefined; + let collectionId = pkiCollectionId; if (caId) { ca = await certificateAuthorityDAL.findById(caId); @@ -1044,6 +1045,7 @@ export const certificateAuthorityServiceFactory = ({ }); } + collectionId = certificateTemplate.pkiCollectionId as string; ca = await certificateAuthorityDAL.findById(certificateTemplate.caId); } @@ -1070,8 +1072,8 @@ export const certificateAuthorityServiceFactory = ({ } // check PKI collection - if (pkiCollectionId) { - const pkiCollection = await pkiCollectionDAL.findById(pkiCollectionId); + if (collectionId) { + const pkiCollection = await pkiCollectionDAL.findById(collectionId); if (!pkiCollection) throw new NotFoundError({ message: "PKI collection not found" }); if (pkiCollection.projectId !== ca.projectId) throw new BadRequestError({ message: "Invalid PKI collection" }); } @@ -1237,10 +1239,10 @@ export const certificateAuthorityServiceFactory = ({ tx ); - if (pkiCollectionId) { + if (collectionId) { await pkiCollectionItemDAL.create( { - pkiCollectionId, + pkiCollectionId: collectionId, certId: cert.id }, tx @@ -1290,6 +1292,7 @@ export const certificateAuthorityServiceFactory = ({ }: TSignCertFromCaDTO) => { let ca: TCertificateAuthorities | undefined; let certificateTemplate: TCertificateTemplates | undefined; + let collectionId = pkiCollectionId; if (caId) { ca = await certificateAuthorityDAL.findById(caId); @@ -1301,6 +1304,7 @@ export const certificateAuthorityServiceFactory = ({ }); } + collectionId = certificateTemplate.pkiCollectionId as string; ca = await certificateAuthorityDAL.findById(certificateTemplate.caId); } @@ -1490,10 +1494,10 @@ export const certificateAuthorityServiceFactory = ({ tx ); - if (pkiCollectionId) { + if (collectionId) { await pkiCollectionItemDAL.create( { - pkiCollectionId, + pkiCollectionId: collectionId, certId: cert.id }, tx diff --git a/backend/src/services/certificate-template/certificate-template-service.ts b/backend/src/services/certificate-template/certificate-template-service.ts index 3b2a5d0ed..212fa05e4 100644 --- a/backend/src/services/certificate-template/certificate-template-service.ts +++ b/backend/src/services/certificate-template/certificate-template-service.ts @@ -28,6 +28,7 @@ export const certificateTemplateServiceFactory = ({ }: TCertificateTemplateServiceFactoryDep) => { const createCertTemplate = async ({ caId, + pkiCollectionId, name, commonName, subjectAlternativeName, @@ -58,6 +59,7 @@ export const certificateTemplateServiceFactory = ({ const certificateTemplate = await certificateTemplateDAL.create({ caId, + pkiCollectionId, name, commonName, subjectAlternativeName, @@ -70,6 +72,7 @@ export const certificateTemplateServiceFactory = ({ const updateCertTemplate = async ({ id, caId, + pkiCollectionId, name, commonName, subjectAlternativeName, @@ -110,6 +113,7 @@ export const certificateTemplateServiceFactory = ({ const updatedCertTemplate = await certificateTemplateDAL.updateById(certTemplate.id, { caId, + pkiCollectionId, commonName, subjectAlternativeName, name, diff --git a/backend/src/services/certificate-template/certificate-template-types.ts b/backend/src/services/certificate-template/certificate-template-types.ts index 498a4cf59..c203b386c 100644 --- a/backend/src/services/certificate-template/certificate-template-types.ts +++ b/backend/src/services/certificate-template/certificate-template-types.ts @@ -2,6 +2,7 @@ import { TProjectPermission } from "@app/lib/types"; export type TCreateCertTemplateDTO = { caId: string; + pkiCollectionId?: string; name: string; commonName: string; subjectAlternativeName: string; @@ -11,6 +12,7 @@ export type TCreateCertTemplateDTO = { export type TUpdateCertTemplateDTO = { id: string; caId?: string; + pkiCollectionId?: string; name?: string; commonName?: string; subjectAlternativeName?: string; diff --git a/frontend/src/hooks/api/certificateTemplates/types.ts b/frontend/src/hooks/api/certificateTemplates/types.ts index 7b7d3a15f..b7cd57a3d 100644 --- a/frontend/src/hooks/api/certificateTemplates/types.ts +++ b/frontend/src/hooks/api/certificateTemplates/types.ts @@ -8,6 +8,7 @@ export type TCertificateTemplateListEntry = { export type TCertificateTemplate = { id: string; caId: string; + pkiCollectionId?: string; name: string; commonName: string; subjectAlternativeName: string; @@ -16,6 +17,7 @@ export type TCertificateTemplate = { export type TCreateCertificateTemplateDTO = { caId: string; + pkiCollectionId?: string; name: string; commonName: string; subjectAlternativeName: string; @@ -26,6 +28,7 @@ export type TCreateCertificateTemplateDTO = { export type TUpdateCertificateTemplateDTO = { id: string; caId?: string; + pkiCollectionId?: string; name?: string; commonName?: string; subjectAlternativeName?: string; diff --git a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateModal.tsx b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateModal.tsx index 40223085b..e5d686134 100644 --- a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateModal.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateModal.tsx @@ -216,60 +216,61 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => { )} /> {(!selectedCertTemplateId || selectedCertTemplateId === CERT_TEMPLATE_NONE_VALUE) && ( - ( - - - - )} - /> - )} - ( - - - + + + )} + /> + ) && ( + ( + + + + )} + /> )} - /> status: CaStatus.ACTIVE }); + const { data: collectionsData } = useListWorkspacePkiCollections({ + workspaceId: currentWorkspace?.id || "" + }); + const { mutateAsync: createCertTemplate } = useCreateCertTemplate(); const { mutateAsync: updateCertTemplate } = useUpdateCertTemplate(); @@ -82,6 +88,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) => name: certTemplate.name, commonName: certTemplate.commonName, subjectAlternativeName: certTemplate.subjectAlternativeName, + collectionId: certTemplate.pkiCollectionId ?? undefined, ttl: certTemplate.ttl }); } else { @@ -96,6 +103,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) => const onFormSubmit = async ({ caId, + collectionId, name, commonName, subjectAlternativeName, @@ -110,6 +118,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) => await updateCertTemplate({ id: certTemplate.id, projectId: currentWorkspace.id, + pkiCollectionId: collectionId, caId, name, commonName, @@ -124,6 +133,7 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) => } else { await createCertTemplate({ projectId: currentWorkspace.id, + pkiCollectionId: collectionId, caId, name, commonName, @@ -200,6 +210,31 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle }: Props) => )} /> + ( + + + + )} + /> { } icon={} > - Manage + Manage Policies