diff --git a/backend/src/db/migrations/20240522010055_certificate-authority.ts b/backend/src/db/migrations/20240522010055_certificate-authority.ts index 6a08878ad..bf887beb9 100644 --- a/backend/src/db/migrations/20240522010055_certificate-authority.ts +++ b/backend/src/db/migrations/20240522010055_certificate-authority.ts @@ -5,7 +5,7 @@ import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils"; export async function up(knex: Knex): Promise { if (!(await knex.schema.hasTable(TableName.CertificateAuthority))) { - // TODO: consider adding algo details + // TODO: add algo deets await knex.schema.createTable(TableName.CertificateAuthority, (t) => { t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); t.timestamps(true, true, true); @@ -77,30 +77,15 @@ export async function up(knex: Knex): Promise { }); } - if (!(await knex.schema.hasTable(TableName.CertificateSecret))) { - await knex.schema.createTable(TableName.CertificateSecret, (t) => { - t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); - t.timestamps(true, true, true); - t.uuid("certId").notNullable().unique(); - t.foreign("certId").references("id").inTable(TableName.Certificate).onDelete("CASCADE"); - t.text("pk").notNullable(); // TODO: encrypt - t.text("sk").notNullable(); // TODO: encrypt - }); - } - await createOnUpdateTrigger(knex, TableName.CertificateAuthority); await createOnUpdateTrigger(knex, TableName.CertificateAuthorityCert); await createOnUpdateTrigger(knex, TableName.CertificateAuthoritySk); await createOnUpdateTrigger(knex, TableName.Certificate); await createOnUpdateTrigger(knex, TableName.CertificateCert); - await createOnUpdateTrigger(knex, TableName.CertificateSecret); } export async function down(knex: Knex): Promise { // certificates - await knex.schema.dropTableIfExists(TableName.CertificateSecret); - await dropOnUpdateTrigger(knex, TableName.CertificateSecret); - await knex.schema.dropTableIfExists(TableName.CertificateCert); await dropOnUpdateTrigger(knex, TableName.CertificateCert); diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index f0253ce67..dfa1fd364 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -73,7 +73,6 @@ import { tokenDALFactory } from "@app/services/auth-token/auth-token-dal"; import { tokenServiceFactory } from "@app/services/auth-token/auth-token-service"; import { certificateCertDALFactory } from "@app/services/certificate/certificate-cert-dal"; import { certificateDALFactory } from "@app/services/certificate/certificate-dal"; -import { certificateSecretDALFactory } from "@app/services/certificate/certificate-secret-dal"; import { certificateServiceFactory } from "@app/services/certificate/certificate-service"; import { certificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal"; import { certificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal"; @@ -502,14 +501,11 @@ export const registerRoutes = async ( const certificateDAL = certificateDALFactory(db); const certificateCertDAL = certificateCertDALFactory(db); - const certificateSecretDAL = certificateSecretDALFactory(db); const certificateService = certificateServiceFactory({ certificateDAL, certificateCertDAL, - certificateSecretDAL, certificateAuthorityDAL, - certificateAuthorityCertDAL, permissionService }); @@ -519,7 +515,6 @@ export const registerRoutes = async ( certificateAuthoritySkDAL, certificateDAL, certificateCertDAL, - certificateSecretDAL, projectDAL, permissionService }); diff --git a/backend/src/server/routes/v1/certificate-router.ts b/backend/src/server/routes/v1/certificate-router.ts index 37714c067..305afebf9 100644 --- a/backend/src/server/routes/v1/certificate-router.ts +++ b/backend/src/server/routes/v1/certificate-router.ts @@ -86,26 +86,21 @@ export const registerCertRouter = async (server: FastifyZodProvider) => { 200: z.object({ certificate: z.string().trim(), certificateChain: z.string().trim(), - issuingCaCertificate: z.string().trim(), - privateKey: z.string().trim(), serialNumber: z.string().trim() }) } }, handler: async (req) => { - const { certificate, certificateChain, issuingCaCertificate, privateKey, serialNumber } = - await server.services.certificate.getCertCert({ - certId: req.params.certId, - actor: req.permission.type, - actorId: req.permission.id, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId - }); + const { certificate, certificateChain, serialNumber } = await server.services.certificate.getCertCert({ + certId: req.params.certId, + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId + }); return { certificate, certificateChain, - issuingCaCertificate, - privateKey, serialNumber }; } diff --git a/backend/src/services/certificate-authority/certificate-authority-service.ts b/backend/src/services/certificate-authority/certificate-authority-service.ts index 22c307710..7d9ea02f8 100644 --- a/backend/src/services/certificate-authority/certificate-authority-service.ts +++ b/backend/src/services/certificate-authority/certificate-authority-service.ts @@ -7,7 +7,6 @@ import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services import { BadRequestError } from "@app/lib/errors"; import { TCertificateCertDALFactory } from "@app/services/certificate/certificate-cert-dal"; import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal"; -import { TCertificateSecretDALFactory } from "@app/services/certificate/certificate-secret-dal"; import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal"; @@ -29,15 +28,16 @@ import { } from "./certificate-authority-types"; type TCertificateAuthorityServiceFactoryDep = { - // TODO: Pick - certificateAuthorityDAL: TCertificateAuthorityDALFactory; - certificateAuthorityCertDAL: TCertificateAuthorityCertDALFactory; - certificateAuthoritySkDAL: TCertificateAuthoritySkDALFactory; - certificateDAL: TCertificateDALFactory; - certificateCertDAL: TCertificateCertDALFactory; - certificateSecretDAL: TCertificateSecretDALFactory; - projectDAL: TProjectDALFactory; - permissionService: TPermissionServiceFactory; + certificateAuthorityDAL: Pick< + TCertificateAuthorityDALFactory, + "transaction" | "create" | "findById" | "updateById" | "deleteById" | "findOne" | "buildCertificateChain" + >; + certificateAuthorityCertDAL: Pick; + certificateAuthoritySkDAL: Pick; + certificateDAL: Pick; + certificateCertDAL: Pick; + projectDAL: Pick; + permissionService: Pick; }; export type TCertificateAuthorityServiceFactory = ReturnType; @@ -48,7 +48,6 @@ export const certificateAuthorityServiceFactory = ({ certificateAuthoritySkDAL, certificateDAL, certificateCertDAL, - certificateSecretDAL, projectDAL, permissionService }: TCertificateAuthorityServiceFactoryDep) => { @@ -624,12 +623,6 @@ export const certificateAuthorityServiceFactory = ({ const chain = await certificateAuthorityDAL.buildCertificateChain(caId); - // https://nodejs.org/api/crypto.html#static-method-keyobjectfromkey - const skObj = KeyObject.from(leafKeys.privateKey); - const sk = skObj.export({ format: "pem", type: "pkcs8" }) as string; - const pkObj = KeyObject.from(leafKeys.publicKey); - const pk = pkObj.export({ format: "pem", type: "spki" }) as string; - await certificateDAL.transaction(async (tx) => { const cert = await certificateDAL.create( { @@ -650,15 +643,6 @@ export const certificateAuthorityServiceFactory = ({ tx ); - await certificateSecretDAL.create( - { - certId: cert.id, - pk, // TODO: encrypt - sk // TODO: encrypt - }, - tx - ); - return cert; }); diff --git a/backend/src/services/certificate/certificate-secret-dal.ts b/backend/src/services/certificate/certificate-secret-dal.ts deleted file mode 100644 index bd0394f78..000000000 --- a/backend/src/services/certificate/certificate-secret-dal.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { TDbClient } from "@app/db"; -import { TableName } from "@app/db/schemas"; -import { ormify } from "@app/lib/knex"; - -export type TCertificateSecretDALFactory = ReturnType; - -export const certificateSecretDALFactory = (db: TDbClient) => { - const certificateSecretOrm = ormify(db, TableName.CertificateSecret); - return certificateSecretOrm; -}; diff --git a/backend/src/services/certificate/certificate-service.ts b/backend/src/services/certificate/certificate-service.ts index 98cb46d24..09e2cc0fe 100644 --- a/backend/src/services/certificate/certificate-service.ts +++ b/backend/src/services/certificate/certificate-service.ts @@ -5,20 +5,15 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { TCertificateCertDALFactory } from "@app/services/certificate/certificate-cert-dal"; import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal"; -import { TCertificateSecretDALFactory } from "@app/services/certificate/certificate-secret-dal"; -import { TCertificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal"; import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal"; import { TDeleteCertDTO, TGetCertCertDTO, TGetCertDTO } from "./certificate-types"; type TCertificateServiceFactoryDep = { - // TODO: Pick - certificateDAL: TCertificateDALFactory; - certificateCertDAL: TCertificateCertDALFactory; - certificateSecretDAL: TCertificateSecretDALFactory; - certificateAuthorityDAL: TCertificateAuthorityDALFactory; - certificateAuthorityCertDAL: TCertificateAuthorityCertDALFactory; - permissionService: TPermissionServiceFactory; + certificateDAL: Pick; + certificateCertDAL: Pick; + certificateAuthorityDAL: Pick; + permissionService: Pick; }; export type TCertificateServiceFactory = ReturnType; @@ -26,9 +21,7 @@ export type TCertificateServiceFactory = ReturnType { const getCertById = async ({ certId, actorId, actorAuthMethod, actor, actorOrgId }: TGetCertDTO) => { @@ -77,19 +70,15 @@ export const certificateServiceFactory = ({ actorAuthMethod, actorOrgId ); - // TODO: re-evaluate this permission - ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Create, ProjectPermissionSub.Certificates); - const caCert = await certificateAuthorityCertDAL.findOne({ caId: ca.id }); + ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Certificates); + const certCert = await certificateCertDAL.findOne({ certId }); - const certSecret = await certificateSecretDAL.findOne({ certId }); const certObj = new x509.X509Certificate(certCert.certificate); return { certificate: certCert.certificate, certificateChain: certCert.certificateChain, - issuingCaCertificate: caCert.certificate, - privateKey: certSecret.sk, serialNumber: certObj.serialNumber }; }; diff --git a/frontend/src/hooks/api/ca/types.ts b/frontend/src/hooks/api/ca/types.ts index 3c7eca11f..02ce1862d 100644 --- a/frontend/src/hooks/api/ca/types.ts +++ b/frontend/src/hooks/api/ca/types.ts @@ -1,4 +1,4 @@ -import { CaStatus,CaType } from "./enums"; +import { CaStatus, CaType } from "./enums"; export type TCertificateAuthority = { id: string; @@ -85,6 +85,6 @@ export type TCreateCertificateResponse = { certificate: string; issuingCertificate: string; certificateChain: string; - sk: string; + privateKey: string; serialNumber: string; }; diff --git a/frontend/src/hooks/api/certificates/queries.tsx b/frontend/src/hooks/api/certificates/queries.tsx index 0001ba3ac..e07ff27e7 100644 --- a/frontend/src/hooks/api/certificates/queries.tsx +++ b/frontend/src/hooks/api/certificates/queries.tsx @@ -29,8 +29,6 @@ export const useGetCertCert = (certId: string) => { const { data } = await apiRequest.get<{ certificate: string; certificateChain: string; - issuingCaCertificate: string; - privateKey: string; serialNumber: string; }>(`/api/v1/certificates/${certId}/certificate`); return data; diff --git a/frontend/src/views/Project/CertificatesPage/components/CaTab/components/CaCertModal.tsx b/frontend/src/views/Project/CertificatesPage/components/CaTab/components/CaCertModal.tsx index df1f10469..97970d94f 100644 --- a/frontend/src/views/Project/CertificatesPage/components/CaTab/components/CaCertModal.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/CaTab/components/CaCertModal.tsx @@ -1,12 +1,9 @@ -import { useEffect } from "react"; -import { faCheck, faCopy, faDownload } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import { IconButton, Modal, ModalContent } from "@app/components/v2"; -import { useToggle } from "@app/hooks"; +import { Modal, ModalContent } from "@app/components/v2"; import { useGetCaCert } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; +import { CertificateContent } from "../../CertificatesTab/components/CertificateContent"; + type Props = { popUp: UsePopUpState<["caCert"]>; handlePopUpToggle: (popUpName: keyof UsePopUpState<["caCert"]>, state?: boolean) => void; @@ -14,39 +11,6 @@ type Props = { export const CaCertModal = ({ popUp, handlePopUpToggle }: Props) => { const { data } = useGetCaCert((popUp?.caCert?.data as { caId: string })?.caId || ""); - const [isSerialNumberCopied, setIsSerialNumberCopied] = useToggle(false); - const [isCertificateCopied, setIsCertificateCopied] = useToggle(false); - const [isCertificateChainCopied, setIsCertificateChainCopied] = useToggle(false); - - useEffect(() => { - let timer: NodeJS.Timeout; - if (isSerialNumberCopied) { - timer = setTimeout(() => setIsSerialNumberCopied.off(), 2000); - } - - if (isCertificateCopied) { - timer = setTimeout(() => setIsCertificateCopied.off(), 2000); - } - - if (isCertificateChainCopied) { - timer = setTimeout(() => setIsCertificateChainCopied.off(), 2000); - } - - return () => clearTimeout(timer); - }, [isSerialNumberCopied, isCertificateCopied, isCertificateChainCopied]); - - const downloadTxtFile = (filename: string, content: string) => { - const blob = new Blob([content], { type: "text/plain" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - }; - return ( { > {data ? ( -
-

Serial Number

-
-

{data.serialNumber}

- { - navigator.clipboard.writeText(data.serialNumber); - setIsSerialNumberCopied.on(); - }} - > - - - Click to copy - - -
- -
-

Certificate Body

-
- { - navigator.clipboard.writeText(data.certificate); - setIsCertificateCopied.on(); - }} - > - - - Copy - - - { - downloadTxtFile("certificate.txt", data.certificate); - }} - > - - - Download - - -
-
-
-

{data.certificate}

-
- {data.certificateChain && ( - <> -
-

Certificate Chain

-
- { - navigator.clipboard.writeText(data.certificateChain); - setIsCertificateChainCopied.on(); - }} - > - - - Copy - - - { - downloadTxtFile("certificate_chain.txt", data.certificate); - }} - > - - - Download - - -
-
-
-

{data.certificateChain}

-
- - )} -
+ ) : (
)} diff --git a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateCertModal.tsx b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateCertModal.tsx index 78777b295..6ea79d180 100644 --- a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateCertModal.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateCertModal.tsx @@ -1,12 +1,9 @@ -import { useEffect } from "react"; -import { faCheck, faCopy, faDownload } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import { IconButton, Modal, ModalContent } from "@app/components/v2"; -import { useToggle } from "@app/hooks"; +import { Modal, ModalContent } from "@app/components/v2"; import { useGetCertCert } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; +import { CertificateContent } from "./CertificateContent"; + type Props = { popUp: UsePopUpState<["certificateCert"]>; handlePopUpToggle: (popUpName: keyof UsePopUpState<["certificateCert"]>, state?: boolean) => void; @@ -17,44 +14,6 @@ export const CertificateCertModal = ({ popUp, handlePopUpToggle }: Props) => { (popUp?.certificateCert?.data as { certId: string })?.certId || "" ); - const [isSerialNumberCopied, setIsSerialNumberCopied] = useToggle(false); - const [isCertificateCopied, setIsCertificateCopied] = useToggle(false); - const [isCertificateChainCopied, setIsCertificateChainCopied] = useToggle(false); - const [isCertificateSkCopied, setIsCertificateSkCopied] = useToggle(false); - - useEffect(() => { - let timer: NodeJS.Timeout; - if (isSerialNumberCopied) { - timer = setTimeout(() => setIsSerialNumberCopied.off(), 2000); - } - - if (isCertificateCopied) { - timer = setTimeout(() => setIsCertificateCopied.off(), 2000); - } - - if (isCertificateChainCopied) { - timer = setTimeout(() => setIsCertificateChainCopied.off(), 2000); - } - - if (isCertificateSkCopied) { - timer = setTimeout(() => setIsCertificateSkCopied.off(), 2000); - } - - return () => clearTimeout(timer); - }, [isSerialNumberCopied, isCertificateCopied, isCertificateChainCopied, isCertificateSkCopied]); - - const downloadTxtFile = (filename: string, content: string) => { - const blob = new Blob([content], { type: "text/plain" }); - const url = URL.createObjectURL(blob); - const a = document.createElement("a"); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - document.body.removeChild(a); - URL.revokeObjectURL(url); - }; - return ( { > {data ? ( -
-

Serial Number

-
-

{data.serialNumber}

- { - navigator.clipboard.writeText(data.serialNumber); - setIsSerialNumberCopied.on(); - }} - > - - - Click to copy - - -
-
-

Certificate Body

-
- { - navigator.clipboard.writeText(data.certificate); - setIsCertificateCopied.on(); - }} - > - - - Copy - - - { - downloadTxtFile("certificate.txt", data.certificate); - }} - > - - - Download - - -
-
-
-

{data.certificate}

-
-
-

Certificate Chain

-
- { - navigator.clipboard.writeText(data.certificateChain); - setIsCertificateChainCopied.on(); - }} - > - - - Copy - - - { - downloadTxtFile("certificate_chain.txt", data.certificate); - }} - > - - - Download - - -
-
-
-

{data.certificateChain}

-
-
-

Certificate Private Key

-
- { - navigator.clipboard.writeText(data.privateKey); - setIsCertificateSkCopied.on(); - }} - > - - - Copy - - - { - downloadTxtFile("private_key.txt", data.privateKey); - }} - > - - - Download - - -
-
-
-

{data.privateKey}

-
-
+ ) : (
)} diff --git a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateContent.tsx b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateContent.tsx new file mode 100644 index 000000000..ac5eb3fd7 --- /dev/null +++ b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateContent.tsx @@ -0,0 +1,190 @@ +import { useEffect } from "react"; +import { faCheck, faCopy, faDownload } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +import { IconButton } from "@app/components/v2"; +import { useToggle } from "@app/hooks"; + +type Props = { + serialNumber: string; + certificate: string; + certificateChain: string; + privateKey?: string; +}; + +export const CertificateContent = ({ + serialNumber, + certificate, + certificateChain, + privateKey +}: Props) => { + const [isSerialNumberCopied, setIsSerialNumberCopied] = useToggle(false); + const [isCertificateCopied, setIsCertificateCopied] = useToggle(false); + const [isCertificateChainCopied, setIsCertificateChainCopied] = useToggle(false); + const [isCertificateSkCopied, setIsCertificateSkCopied] = useToggle(false); + + useEffect(() => { + let timer: NodeJS.Timeout; + if (isSerialNumberCopied) { + timer = setTimeout(() => setIsSerialNumberCopied.off(), 2000); + } + + if (isCertificateCopied) { + timer = setTimeout(() => setIsCertificateCopied.off(), 2000); + } + + if (isCertificateChainCopied) { + timer = setTimeout(() => setIsCertificateChainCopied.off(), 2000); + } + + if (isCertificateSkCopied) { + timer = setTimeout(() => setIsCertificateSkCopied.off(), 2000); + } + + return () => clearTimeout(timer); + }, [isSerialNumberCopied, isCertificateCopied, isCertificateChainCopied, isCertificateSkCopied]); + + const downloadTxtFile = (filename: string, content: string) => { + const blob = new Blob([content], { type: "text/plain" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + }; + + return ( +
+

Serial Number

+
+

{serialNumber}

+ { + navigator.clipboard.writeText(serialNumber); + setIsSerialNumberCopied.on(); + }} + > + + + Click to copy + + +
+
+

Certificate Body

+
+ { + navigator.clipboard.writeText(certificate); + setIsCertificateCopied.on(); + }} + > + + + Copy + + + { + downloadTxtFile("certificate.txt", certificate); + }} + > + + + Download + + +
+
+
+

{certificate}

+
+
+

Certificate Chain

+
+ { + navigator.clipboard.writeText(certificateChain); + setIsCertificateChainCopied.on(); + }} + > + + + Copy + + + { + downloadTxtFile("certificate_chain.txt", certificate); + }} + > + + + Download + + +
+
+
+

{certificateChain}

+
+ {privateKey && ( + <> +
+

Certificate Private Key

+
+ { + navigator.clipboard.writeText(privateKey); + setIsCertificateSkCopied.on(); + }} + > + + + Copy + + + { + downloadTxtFile("private_key.txt", privateKey); + }} + > + + + Download + + +
+
+
+

{privateKey}

+
+ + )} +
+ ); +}; 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 a740b9063..6fd27d145 100644 --- a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateModal.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateModal.tsx @@ -1,4 +1,4 @@ -import { useEffect } from "react"; +import { useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { format } from "date-fns"; @@ -24,6 +24,8 @@ import { import { caTypeToNameMap } from "@app/hooks/api/ca/constants"; import { UsePopUpState } from "@app/hooks/usePopUp"; +import { CertificateContent } from "./CertificateContent"; + const isValidDate = (dateString: string) => { if (dateString === "") return true; const date = new Date(dateString); @@ -48,7 +50,15 @@ type Props = { handlePopUpToggle: (popUpName: keyof UsePopUpState<["certificate"]>, state?: boolean) => void; }; +type TCertificateDetails = { + serialNumber: string; + certificate: string; + certificateChain: string; + privateKey: string; +}; + export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => { + const [certificateDetails, setCertificateDetails] = useState(null); const { currentWorkspace } = useWorkspace(); const { data: cert } = useGetCertById( (popUp?.certificate?.data as { certId: string })?.certId || "" @@ -93,7 +103,7 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => { try { if (!currentWorkspace?.slug) return; - await createCertificate({ + const { serialNumber, certificate, certificateChain, privateKey } = await createCertificate({ projectSlug: currentWorkspace.slug, caId, commonName, @@ -103,7 +113,13 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => { }); reset(); - handlePopUpToggle("certificate", false); + + setCertificateDetails({ + serialNumber, + certificate, + certificateChain, + privateKey + }); createNotification({ text: "Successfully created certificate", @@ -122,7 +138,7 @@ export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => { if (cas?.length) { setValue("caId", cas[0].id); } - }, [cas, setValue]); + }, [cas]); return ( { onOpenChange={(isOpen) => { handlePopUpToggle("certificate", isOpen); reset(); + setCertificateDetails(null); }} > -
- ( - - - + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + ( + + + + )} + /> + {!cert && ( +
+ + +
)} + + ) : ( + - ( - - - - )} - /> - ( - - - - )} - /> - ( - - - - )} - /> - {!cert && ( -
- - -
- )} - + )}
);