diff --git a/backend/src/server/routes/v1/certificate-router.ts b/backend/src/server/routes/v1/certificate-router.ts index 492902a6f..f14ff437f 100644 --- a/backend/src/server/routes/v1/certificate-router.ts +++ b/backend/src/server/routes/v1/certificate-router.ts @@ -11,12 +11,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { addNoCacheHeaders } from "@app/server/lib/caching"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; -import { - ACMESANType, - CertKeyAlgorithm, - CertSignatureAlgorithm, - CrlReason -} from "@app/services/certificate/certificate-types"; +import { CertKeyAlgorithm, CertSignatureAlgorithm, CrlReason } from "@app/services/certificate/certificate-types"; import { CaType } from "@app/services/certificate-authority/certificate-authority-enums"; import { validateCaDateField } from "@app/services/certificate-authority/certificate-authority-validators"; import { @@ -129,18 +124,6 @@ export const registerCertificateRouter = async (server: FastifyZodProvider) => { .optional(), signatureAlgorithm: z.nativeEnum(CertSignatureAlgorithm).optional(), keyAlgorithm: z.nativeEnum(CertKeyAlgorithm).optional(), - subjectAlternativeNames: z - .array( - z.object({ - type: z.nativeEnum(ACMESANType), - value: z - .string() - .trim() - .min(1, "SAN value cannot be empty") - .max(255, "SAN value must be less than 255 characters") - }) - ) - .optional(), ttl: z .string() .trim() @@ -199,19 +182,9 @@ export const registerCertificateRouter = async (server: FastifyZodProvider) => { useOrderFlow = caType !== CaType.INTERNAL; } - if (attributes?.subjectAlternativeNames?.length || useOrderFlow) { - let acmeAltNames: Array<{ type: ACMESANType; value: string }> | undefined = attributes?.subjectAlternativeNames; - if (useOrderFlow && !attributes?.subjectAlternativeNames && attributes?.altNames?.length) { - acmeAltNames = attributes.altNames.map((alt: { type: CertSubjectAlternativeNameType; value: string }) => ({ - type: (alt.type === CertSubjectAlternativeNameType.DNS_NAME - ? ACMESANType.DNS - : ACMESANType.IP) as ACMESANType, - value: alt.value - })); - } - + if (useOrderFlow) { const certificateOrderObject = { - altNames: acmeAltNames || [], + altNames: attributes?.altNames || [], validity: { ttl: attributes?.ttl || "" }, commonName: attributes?.commonName, keyUsages: attributes?.keyUsages, @@ -579,7 +552,7 @@ export const registerCertificateRouter = async (server: FastifyZodProvider) => { profileId: z.string().uuid(), subjectAlternativeNames: z.array( z.object({ - type: z.nativeEnum(ACMESANType), + type: z.nativeEnum(CertSubjectAlternativeNameType), value: z .string() .trim() diff --git a/backend/src/server/routes/v3/deprecated-certificates-router.ts b/backend/src/server/routes/v3/deprecated-certificates-router.ts index fc3a05ecb..ab8ae176c 100644 --- a/backend/src/server/routes/v3/deprecated-certificates-router.ts +++ b/backend/src/server/routes/v3/deprecated-certificates-router.ts @@ -7,7 +7,7 @@ import { ms } from "@app/lib/ms"; import { writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { AuthMode } from "@app/services/auth/auth-type"; -import { ACMESANType, CertKeyAlgorithm, CertSignatureAlgorithm } from "@app/services/certificate/certificate-types"; +import { CertKeyAlgorithm, CertSignatureAlgorithm } from "@app/services/certificate/certificate-types"; import { validateCaDateField } from "@app/services/certificate-authority/certificate-authority-validators"; import { CertExtendedKeyUsageType, @@ -305,7 +305,7 @@ export const registerCertificatesRouter = async (server: FastifyZodProvider) => profileId: z.string().uuid(), subjectAlternativeNames: z.array( z.object({ - type: z.nativeEnum(ACMESANType), + type: z.nativeEnum(CertSubjectAlternativeNameType), value: z .string() .trim() diff --git a/backend/src/services/certificate-authority/certificate-issuance-queue.ts b/backend/src/services/certificate-authority/certificate-issuance-queue.ts index 13fd68804..f590f2850 100644 --- a/backend/src/services/certificate-authority/certificate-issuance-queue.ts +++ b/backend/src/services/certificate-authority/certificate-issuance-queue.ts @@ -208,7 +208,7 @@ export const certificateIssuanceQueueFactory = ({ const [, generatedCsr] = await acme.crypto.createCsr( { - altNames: altNames || [], + altNames: altNames ? [...altNames] : [], commonName: commonName || "" }, skLeaf diff --git a/backend/src/services/certificate-v3/certificate-v3-service.test.ts b/backend/src/services/certificate-v3/certificate-v3-service.test.ts index b3db6f736..9d8d1aebb 100644 --- a/backend/src/services/certificate-v3/certificate-v3-service.test.ts +++ b/backend/src/services/certificate-v3/certificate-v3-service.test.ts @@ -11,7 +11,7 @@ import { TPkiAcmeAccountDALFactory } from "@app/ee/services/pki-acme/pki-acme-ac import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors"; import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal"; import { TCertificateSecretDALFactory } from "@app/services/certificate/certificate-secret-dal"; -import { ACMESANType, CertStatus } from "@app/services/certificate/certificate-types"; +import { CertStatus } from "@app/services/certificate/certificate-types"; import { TCertificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal"; import { CaStatus } from "@app/services/certificate-authority/certificate-authority-enums"; import { TInternalCertificateAuthorityServiceFactory } from "@app/services/certificate-authority/internal/internal-certificate-authority-service"; @@ -19,7 +19,8 @@ import { CertExtendedKeyUsageType, CertIncludeType, CertKeyUsageType, - CertSubjectAttributeType + CertSubjectAttributeType, + CertSubjectAlternativeNameType } from "@app/services/certificate-common/certificate-constants"; import { TCertificateProfileDALFactory } from "@app/services/certificate-profile/certificate-profile-dal"; import { EnrollmentType, IssuerType } from "@app/services/certificate-profile/certificate-profile-types"; @@ -853,7 +854,7 @@ describe("CertificateV3Service", () => { describe("orderCertificateFromProfile", () => { const mockCertificateOrder = { - altNames: [{ type: ACMESANType.DNS, value: "example.com" }], + altNames: [{ type: CertSubjectAlternativeNameType.DNS_NAME, value: "example.com" }], validity: { ttl: "30d" }, commonName: "example.com", keyUsages: [CertKeyUsageType.DIGITAL_SIGNATURE], diff --git a/backend/src/services/certificate-v3/certificate-v3-service.ts b/backend/src/services/certificate-v3/certificate-v3-service.ts index fd3b85e76..20e5d3e1c 100644 --- a/backend/src/services/certificate-v3/certificate-v3-service.ts +++ b/backend/src/services/certificate-v3/certificate-v3-service.ts @@ -1054,7 +1054,7 @@ export const certificateV3ServiceFactory = ({ tx }); - const certificateRecord = await certificateDAL.findById(certResult.certificateId); + const certificateRecord = await certificateDAL.findById(certResult.certificateId, tx); if (!certificateRecord) { throw new NotFoundError({ message: "Certificate was issued but could not be found in database" }); } @@ -1307,25 +1307,7 @@ export const certificateV3ServiceFactory = ({ commonName: certificateOrder.commonName, keyUsages: certificateOrder.keyUsages, extendedKeyUsages: certificateOrder.extendedKeyUsages, - subjectAlternativeNames: certificateOrder.altNames?.map((san) => { - let certType: CertSubjectAlternativeNameType; - switch (san.type) { - case "dns": - certType = CertSubjectAlternativeNameType.DNS_NAME; - break; - case "ip": - certType = CertSubjectAlternativeNameType.IP_ADDRESS; - break; - default: - throw new BadRequestError({ - message: `Unsupported Subject Alternative Name type: ${san.type as string}` - }); - } - return { - type: certType, - value: san.value - }; - }), + subjectAlternativeNames: certificateOrder.altNames, validity: certificateOrder.validity, notBefore: certificateOrder.notBefore, notAfter: certificateOrder.notAfter, diff --git a/backend/src/services/certificate-v3/certificate-v3-types.ts b/backend/src/services/certificate-v3/certificate-v3-types.ts index 6ea57c6a0..50d710406 100644 --- a/backend/src/services/certificate-v3/certificate-v3-types.ts +++ b/backend/src/services/certificate-v3/certificate-v3-types.ts @@ -1,6 +1,5 @@ import { TProjectPermission } from "@app/lib/types"; -import { ACMESANType } from "../certificate/certificate-types"; import { CertExtendedKeyUsageType, CertKeyUsageType, @@ -45,7 +44,7 @@ export type TOrderCertificateFromProfileDTO = { profileId: string; certificateOrder: { altNames: Array<{ - type: ACMESANType; + type: CertSubjectAlternativeNameType; value: string; }>; validity: { diff --git a/frontend/src/hooks/api/certificates/index.tsx b/frontend/src/hooks/api/certificates/index.tsx index 19882d8c3..bc7f80d2c 100644 --- a/frontend/src/hooks/api/certificates/index.tsx +++ b/frontend/src/hooks/api/certificates/index.tsx @@ -7,4 +7,4 @@ export { useRevokeCert, useUpdateRenewalConfig } from "./mutations"; -export { useGetCert, useGetCertBody, useGetCertificateRequest } from "./queries"; +export { useGetCert, useGetCertBody } from "./queries"; diff --git a/frontend/src/hooks/api/certificates/queries.tsx b/frontend/src/hooks/api/certificates/queries.tsx index 9b6205e2d..13245894b 100644 --- a/frontend/src/hooks/api/certificates/queries.tsx +++ b/frontend/src/hooks/api/certificates/queries.tsx @@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { TCertificate, TCertificateRequestDetails } from "./types"; +import { TCertificate } from "./types"; export const certKeys = { getCertById: (serialNumber: string) => [{ serialNumber }, "cert"], @@ -59,23 +59,3 @@ export const useGetCertBundle = (serialNumber: string) => { enabled: Boolean(serialNumber) }); }; - -export const useGetCertificateRequest = (requestId: string, projectSlug: string) => { - return useQuery({ - queryKey: certKeys.getCertificateRequest(requestId, projectSlug), - queryFn: async () => { - const { data } = await apiRequest.get( - `/api/v3/pki/certificates/requests/${requestId}`, - { - params: { projectSlug } - } - ); - return data; - }, - enabled: Boolean(requestId) && Boolean(projectSlug), - refetchInterval: (query) => { - // Only refetch if status is pending - return query.state.data?.status === "pending" ? 5000 : false; - } - }); -}; diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRequestTracker.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRequestTracker.tsx deleted file mode 100644 index 2d6453963..000000000 --- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificateRequestTracker.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { useEffect } from "react"; -import { faCheck, faExclamationTriangle, faSpinner } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import { useProject } from "@app/context"; -import { useGetCertificateRequest } from "@app/hooks/api/certificates"; - -type CertificateInfo = { - id: string; - serialNumber: string; - commonName: string; - notAfter: string; - [key: string]: unknown; -}; - -type Props = { - requestId: string; - onCertificateIssued?: (certificate: CertificateInfo) => void; -}; - -export const CertificateRequestTracker = ({ requestId, onCertificateIssued }: Props) => { - const { currentProject } = useProject(); - - const { data: requestData, isLoading } = useGetCertificateRequest( - requestId, - currentProject?.slug || "" - ); - - useEffect(() => { - if (requestData?.status === "issued" && requestData.certificate && onCertificateIssued) { - onCertificateIssued(requestData.certificate); - } - }, [requestData, onCertificateIssued]); - - if (isLoading) { - return ( -
- - Loading request status... -
- ); - } - - const getStatusIcon = () => { - switch (requestData?.status) { - case "pending": - return ; - case "issued": - return ; - case "failed": - return ; - default: - return null; - } - }; - - const getStatusMessage = () => { - switch (requestData?.status) { - case "pending": - return "Certificate request is being processed..."; - case "issued": - return "Certificate has been issued successfully!"; - case "failed": - return `Certificate request failed: ${requestData.errorMessage || "Unknown error"}`; - default: - return "Unknown status"; - } - }; - - return ( -
-
- {getStatusIcon()} - - Certificate Request ID: {requestId} - -
- -
- Status: {requestData?.status || "Unknown"} -
- -
{getStatusMessage()}
- - {requestData?.status === "issued" && requestData.certificate && ( -
-
- Certificate Details: -
- Serial Number: {requestData.certificate.serialNumber} -
- Common Name: {requestData.certificate.commonName} -
- Valid Until: {new Date(requestData.certificate.notAfter).toLocaleDateString()} -
-
- )} - - {requestData?.status === "failed" && requestData.errorMessage && ( -
-
- Error Details: -
- {requestData.errorMessage} -
-
- )} -
- ); -};