Minor improvements on self signed certificates

This commit is contained in:
Carlos Monastyrski
2025-11-24 11:20:21 -03:00
parent c0060c1d22
commit d69a2db80c
10 changed files with 491 additions and 237 deletions

View File

@@ -739,11 +739,7 @@ export const pkiAcmeServiceFactory = ({
throw new AcmeBadCSRError({ message: "Invalid CSR: Common name + SANs mismatch with order identifiers" });
}
if (!profile.caId) {
throw new NotFoundError({ message: "Self-signed certificates are not supported for ACME enrollment" });
}
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(profile.caId);
const ca = await certificateAuthorityDAL.findByIdWithAssociatedCa(profile.caId!);
if (!ca) {
throw new NotFoundError({ message: "Certificate Authority not found" });
}

View File

@@ -51,58 +51,100 @@ export const registerCertificateProfilesRouter = async (server: FastifyZodProvid
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.EST) {
if (!data.estConfig) {
return false;
return !!data.estConfig;
}
if (data.apiConfig) {
return false;
}
if (data.acmeConfig) {
return false;
}
}
if (data.enrollmentType === EnrollmentType.API) {
if (!data.apiConfig) {
return false;
}
if (data.estConfig) {
return false;
}
if (data.acmeConfig) {
return false;
}
}
if (data.enrollmentType === EnrollmentType.ACME) {
if (!data.acmeConfig) {
return false;
}
if (data.estConfig) {
return false;
}
if (data.apiConfig) {
return false;
}
}
if (data.issuerType === IssuerType.CA) {
if (!data.caId) {
return false;
}
}
if (data.issuerType === IssuerType.SELF_SIGNED) {
if (data.caId) {
return false;
}
if (data.enrollmentType !== EnrollmentType.API) {
return false;
}
}
return true;
},
{
message:
"EST enrollment type requires EST configuration and cannot have API or ACME configuration. API enrollment type requires API configuration and cannot have EST or ACME configuration. ACME enrollment type requires ACME configuration and cannot have EST or API configuration. CA issuer type requires a CA ID. Self-signed issuer type cannot have a CA ID and only supports API enrollment."
message: "EST enrollment type requires EST configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.API) {
return !!data.apiConfig;
}
return true;
},
{
message: "API enrollment type requires API configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.ACME) {
return !!data.acmeConfig;
}
return true;
},
{
message: "ACME enrollment type requires ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.EST) {
return !data.apiConfig && !data.acmeConfig;
}
return true;
},
{
message: "EST enrollment type cannot have API or ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.API) {
return !data.estConfig && !data.acmeConfig;
}
return true;
},
{
message: "API enrollment type cannot have EST or ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.ACME) {
return !data.estConfig && !data.apiConfig;
}
return true;
},
{
message: "ACME enrollment type cannot have EST or API configuration"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.CA) {
return !!data.caId;
}
return true;
},
{
message: "CA issuer type requires a CA ID"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.SELF_SIGNED) {
return !data.caId;
}
return true;
},
{
message: "Self-signed issuer type cannot have a CA ID"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.SELF_SIGNED) {
return data.enrollmentType === EnrollmentType.API;
}
return true;
},
{
message: "Self-signed issuer type only supports API enrollment"
}
),
response: {

View File

@@ -7,11 +7,7 @@ import { EnrollmentType, IssuerType } from "./certificate-profile-types";
export const createCertificateProfileSchema = z
.object({
projectId: z.string().uuid("Project ID must be valid"),
caId: z
.union([z.string().uuid(), z.literal("")])
.optional()
.nullable()
.transform((val) => (val === "" ? null : val)),
caId: z.string().uuid().nullable().optional(),
certificateTemplateId: z.string().uuid(),
slug: z
.string()
@@ -38,60 +34,101 @@ export const createCertificateProfileSchema = z
})
.refine(
(data) => {
// Validate enrollment type configurations
if (data.enrollmentType === EnrollmentType.EST) {
if (!data.estConfig) {
return false;
return !!data.estConfig;
}
if (data.apiConfig) {
return false;
}
if (data.acmeConfig) {
return false;
}
}
if (data.enrollmentType === EnrollmentType.API) {
if (!data.apiConfig) {
return false;
}
if (data.estConfig) {
return false;
}
if (data.acmeConfig) {
return false;
}
}
if (data.enrollmentType === EnrollmentType.ACME) {
if (!data.acmeConfig) {
return false;
}
if (data.estConfig) {
return false;
}
if (data.apiConfig) {
return false;
}
}
if (data.issuerType === IssuerType.CA) {
if (!data.caId) {
return false;
}
}
if (data.issuerType === IssuerType.SELF_SIGNED) {
if (data.caId) {
return false;
}
if (data.enrollmentType !== EnrollmentType.API) {
return false;
}
}
return true;
},
{
message:
"EST enrollment type requires EST configuration and cannot have API configuration. API enrollment type requires API configuration and cannot have EST configuration. CA issuer type requires a CA ID. Self-signed issuer type cannot have a CA ID and only supports API enrollment."
message: "EST enrollment type requires EST configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.API) {
return !!data.apiConfig;
}
return true;
},
{
message: "API enrollment type requires API configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.ACME) {
return !!data.acmeConfig;
}
return true;
},
{
message: "ACME enrollment type requires ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.EST) {
return !data.apiConfig && !data.acmeConfig;
}
return true;
},
{
message: "EST enrollment type cannot have API or ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.API) {
return !data.estConfig && !data.acmeConfig;
}
return true;
},
{
message: "API enrollment type cannot have EST or ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.ACME) {
return !data.estConfig && !data.apiConfig;
}
return true;
},
{
message: "ACME enrollment type cannot have EST or API configuration"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.CA) {
return !!data.caId;
}
return true;
},
{
message: "CA issuer type requires a CA ID"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.SELF_SIGNED) {
return !data.caId;
}
return true;
},
{
message: "Self-signed issuer type cannot have a CA ID"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.SELF_SIGNED) {
return data.enrollmentType === EnrollmentType.API;
}
return true;
},
{
message: "Self-signed issuer type only supports API enrollment"
}
);
@@ -123,27 +160,34 @@ export const updateCertificateProfileSchema = z
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.EST) {
if (data.apiConfig) {
return false;
return !data.apiConfig;
}
}
if (data.enrollmentType === EnrollmentType.API) {
if (data.estConfig) {
return false;
}
}
if (data.issuerType === IssuerType.SELF_SIGNED) {
if (data.enrollmentType && data.enrollmentType !== EnrollmentType.API) {
return false;
}
}
return true;
},
{
message:
"Cannot have EST config with API enrollment type or API config with EST enrollment type. Self-signed issuer type only supports API enrollment."
message: "EST enrollment type cannot have API configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.API) {
return !data.estConfig;
}
return true;
},
{
message: "API enrollment type cannot have EST configuration"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.SELF_SIGNED) {
return !data.enrollmentType || data.enrollmentType === EnrollmentType.API;
}
return true;
},
{
message: "Self-signed issuer type only supports API enrollment"
}
);

View File

@@ -407,11 +407,16 @@ const generateSelfSignedCertificate = async ({
const signatureAlgorithmConfig = signatureAlgorithmToAlgCfg(effectiveSignatureAlgorithm, effectiveKeyAlgorithm);
const notBeforeDate = certificateRequest.notBefore ? new Date(certificateRequest.notBefore) : new Date();
let notAfterDate = new Date(new Date().setFullYear(new Date().getFullYear() + 1));
let notAfterDate: Date;
if (certificateRequest.notAfter) {
notAfterDate = new Date(certificateRequest.notAfter);
} else if (certificateRequest.validity.ttl) {
notAfterDate = new Date(new Date().getTime() + ms(certificateRequest.validity.ttl));
} else {
throw new BadRequestError({
message: "Either notAfter date or TTL must be provided for certificate validity"
});
}
const serialNumber = createSerialNumber();
@@ -458,10 +463,22 @@ const generateSelfSignedCertificate = async ({
...(subjectAlternativeNames
? [
new x509.SubjectAlternativeNameExtension(
certificateRequest.altNames?.map((san) => ({
type: san.type === CertSubjectAlternativeNameType.DNS_NAME ? "dns" : "ip",
value: san.value
})) || [],
certificateRequest.altNames?.map((san) => {
switch (san.type) {
case CertSubjectAlternativeNameType.DNS_NAME:
return { type: "dns" as const, value: san.value };
case CertSubjectAlternativeNameType.IP_ADDRESS:
return { type: "ip" as const, value: san.value };
case CertSubjectAlternativeNameType.EMAIL:
return { type: "email" as const, value: san.value };
case CertSubjectAlternativeNameType.URI:
return { type: "url" as const, value: san.value };
default:
throw new BadRequestError({
message: `Unsupported Subject Alternative Name type: ${san.type as string}`
});
}
}) || [],
false
)
]
@@ -545,7 +562,7 @@ const createSelfSignedCertificateRecord = async ({
(selfSignedResult.certificateSubject.common_name as string) ||
certificateRequest.commonName ||
originalCert?.commonName ||
(isRenewal ? "Renewed Self-signed Certificate" : "Self-signed Certificate");
"";
const altNamesList = selfSignedResult.subjectAlternativeNames.map((san) => san.value).join(",");
@@ -726,8 +743,8 @@ const processSelfSignedCertificate = async ({
await createEncryptedCertificateData({
certificateId: certificateData.id,
certificate: Buffer.from(selfSignedResult.certificate),
privateKey: Buffer.from(selfSignedResult.privateKey),
certificate: selfSignedResult.certificate,
privateKey: selfSignedResult.privateKey,
projectId,
certificateBodyDAL,
certificateSecretDAL,
@@ -1100,10 +1117,25 @@ export const certificateV3ServiceFactory = ({
commonName: certificateOrder.commonName,
keyUsages: certificateOrder.keyUsages,
extendedKeyUsages: certificateOrder.extendedKeyUsages,
subjectAlternativeNames: certificateOrder.altNames.map((san) => ({
type: san.type === "dns" ? CertSubjectAlternativeNameType.DNS_NAME : CertSubjectAlternativeNameType.IP_ADDRESS,
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
})),
};
}),
validity: certificateOrder.validity,
notBefore: certificateOrder.notBefore,
notAfter: certificateOrder.notAfter,
@@ -1216,7 +1248,8 @@ export const certificateV3ServiceFactory = ({
if (profile.enrollmentType !== EnrollmentType.API) {
throw new ForbiddenRequestError({
message: "Certificate is not eligible for renewal: EST certificates cannot be renewed through this endpoint"
message:
"Certificate is not eligible for renewal: Only certificates issued from an API enrollment profile can be renewed through this endpoint"
});
}
}

View File

@@ -10,4 +10,4 @@ export {
useGetProfileCertificates,
useListCertificateProfiles
} from "./queries";
export type * from "./types";
export * from "./types";

View File

@@ -1,3 +1,14 @@
export enum EnrollmentType {
API = "api",
EST = "est",
ACME = "acme"
}
export enum IssuerType {
CA = "ca",
SELF_SIGNED = "self-signed"
}
export type TCertificateProfile = {
id: string;
projectId: string;
@@ -5,8 +16,8 @@ export type TCertificateProfile = {
certificateTemplateId: string;
slug: string;
description?: string;
enrollmentType: "api" | "est" | "acme";
issuerType: "ca" | "self-signed";
enrollmentType: EnrollmentType;
issuerType: IssuerType;
estConfigId?: string;
apiConfigId?: string;
createdAt: string;
@@ -49,8 +60,8 @@ export type TCreateCertificateProfileDTO = {
certificateTemplateId: string;
slug: string;
description?: string;
enrollmentType: "api" | "est" | "acme";
issuerType: "ca" | "self-signed";
enrollmentType: EnrollmentType;
issuerType: IssuerType;
estConfig?: {
disableBootstrapCaValidation?: boolean;
passphrase: string;
@@ -67,8 +78,8 @@ export type TUpdateCertificateProfileDTO = {
profileId: string;
slug?: string;
description?: string;
enrollmentType?: "api" | "est" | "acme";
issuerType?: "ca" | "self-signed";
enrollmentType?: EnrollmentType;
issuerType?: IssuerType;
estConfig?: {
disableBootstrapCaValidation?: boolean;
passphrase?: string;
@@ -91,8 +102,8 @@ export type TListCertificateProfilesDTO = {
offset?: number;
search?: string;
includeConfigs?: boolean;
enrollmentType?: "api" | "est" | "acme";
issuerType?: "ca" | "self-signed";
enrollmentType?: EnrollmentType;
issuerType?: IssuerType;
caId?: string;
};

View File

@@ -21,7 +21,7 @@ import {
import { useProject } from "@app/context";
import { useGetCert } from "@app/hooks/api";
import { useCreateCertificateV3 } from "@app/hooks/api/ca";
import { useListCertificateProfiles } from "@app/hooks/api/certificateProfiles";
import { EnrollmentType, useListCertificateProfiles } from "@app/hooks/api/certificateProfiles";
import { CertExtendedKeyUsage, CertKeyUsage } from "@app/hooks/api/certificates/enums";
import { useGetCertificateTemplateV2ById } from "@app/hooks/api/certificateTemplates/queries";
import { UsePopUpState } from "@app/hooks/usePopUp";
@@ -122,7 +122,7 @@ export const CertificateIssuanceModal = ({ popUp, handlePopUpToggle, profileId }
const { data: profilesData } = useListCertificateProfiles({
projectId: currentProject?.id || "",
enrollmentType: "api"
enrollmentType: EnrollmentType.API
});
const { mutateAsync: createCertificate } = useCreateCertificateV3({

View File

@@ -21,6 +21,8 @@ import {
import { useProject, useSubscription } from "@app/context";
import { useListCasByProjectId } from "@app/hooks/api/ca/queries";
import {
EnrollmentType,
IssuerType,
TCertificateProfileWithDetails,
TCreateCertificateProfileDTO,
TUpdateCertificateProfileDTO,
@@ -46,8 +48,8 @@ const createSchema = z
.trim()
.max(1000, "Description must be less than 1000 characters")
.optional(),
enrollmentType: z.enum(["api", "est", "acme"]),
issuerType: z.enum(["ca", "self-signed"]),
enrollmentType: z.nativeEnum(EnrollmentType),
issuerType: z.nativeEnum(IssuerType),
certificateAuthorityId: z.string().nullable().optional(),
certificateTemplateId: z.string().min(1, "Certificate Template is required"),
estConfig: z
@@ -79,30 +81,101 @@ const createSchema = z
})
.refine(
(data) => {
if (data.enrollmentType === "est" && !data.estConfig) {
return false;
if (data.enrollmentType === EnrollmentType.EST) {
return !!data.estConfig;
}
if (data.enrollmentType === "api" && !data.apiConfig) {
return false;
}
if (data.enrollmentType === "acme" && !data.acmeConfig) {
return false;
}
if (data.issuerType === "ca" && !data.certificateAuthorityId) {
return false;
}
if (data.issuerType === "self-signed" && data.certificateAuthorityId) {
return false;
}
if (data.issuerType === "self-signed" && data.enrollmentType !== "api") {
return false;
}
return true;
},
{
message: "Configuration is required for selected enrollment type and issuer type"
message: "EST enrollment type requires EST configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.API) {
return !!data.apiConfig;
}
return true;
},
{
message: "API enrollment type requires API configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.ACME) {
return !!data.acmeConfig;
}
return true;
},
{
message: "ACME enrollment type requires ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.EST) {
return !data.apiConfig && !data.acmeConfig;
}
return true;
},
{
message: "EST enrollment type cannot have API or ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.API) {
return !data.estConfig && !data.acmeConfig;
}
return true;
},
{
message: "API enrollment type cannot have EST or ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.ACME) {
return !data.estConfig && !data.apiConfig;
}
return true;
},
{
message: "ACME enrollment type cannot have EST or API configuration"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.CA) {
return !!data.certificateAuthorityId;
}
return true;
},
{
message: "CA issuer type requires a certificate authority"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.SELF_SIGNED) {
return !data.certificateAuthorityId;
}
return true;
},
{
message: "Self-signed issuer type cannot have a certificate authority"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.SELF_SIGNED) {
return data.enrollmentType === EnrollmentType.API;
}
return true;
},
{
message: "Self-signed issuer type only supports API enrollment"
}
);
@@ -122,8 +195,8 @@ const editSchema = z
.trim()
.max(1000, "Description must be less than 1000 characters")
.optional(),
enrollmentType: z.enum(["api", "est", "acme"]),
issuerType: z.enum(["ca", "self-signed"]),
enrollmentType: z.nativeEnum(EnrollmentType),
issuerType: z.nativeEnum(IssuerType),
certificateAuthorityId: z.string().nullable().optional(),
certificateTemplateId: z.string().optional(),
estConfig: z
@@ -143,31 +216,101 @@ const editSchema = z
})
.refine(
(data) => {
if (data.enrollmentType === "est" && !data.estConfig) {
return false;
if (data.enrollmentType === EnrollmentType.EST) {
return !!data.estConfig;
}
if (data.enrollmentType === "api" && !data.apiConfig) {
return false;
}
if (data.enrollmentType === "acme" && !data.acmeConfig) {
return false;
}
if (data.issuerType === "ca" && !data.certificateAuthorityId) {
return false;
}
if (data.issuerType === "self-signed" && data.certificateAuthorityId) {
return false;
}
if (data.issuerType === "self-signed" && data.enrollmentType !== "api") {
return false;
}
return true;
},
{
message:
"Configuration is required for selected enrollment type and issuer type. CA issuer requires a certificate authority. Self-signed issuer cannot have a certificate authority and only supports API enrollment."
message: "EST enrollment type requires EST configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.API) {
return !!data.apiConfig;
}
return true;
},
{
message: "API enrollment type requires API configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.ACME) {
return !!data.acmeConfig;
}
return true;
},
{
message: "ACME enrollment type requires ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.EST) {
return !data.apiConfig && !data.acmeConfig;
}
return true;
},
{
message: "EST enrollment type cannot have API or ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.API) {
return !data.estConfig && !data.acmeConfig;
}
return true;
},
{
message: "API enrollment type cannot have EST or ACME configuration"
}
)
.refine(
(data) => {
if (data.enrollmentType === EnrollmentType.ACME) {
return !data.estConfig && !data.apiConfig;
}
return true;
},
{
message: "ACME enrollment type cannot have EST or API configuration"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.CA) {
return !!data.certificateAuthorityId;
}
return true;
},
{
message: "CA issuer type requires a certificate authority"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.SELF_SIGNED) {
return !data.certificateAuthorityId;
}
return true;
},
{
message: "Self-signed issuer type cannot have a certificate authority"
}
)
.refine(
(data) => {
if (data.issuerType === IssuerType.SELF_SIGNED) {
return data.enrollmentType === EnrollmentType.API;
}
return true;
},
{
message: "Self-signed issuer type only supports API enrollment"
}
);
@@ -222,7 +365,7 @@ export const CreateProfileModal = ({
certificateAuthorityId: profile.caId || undefined,
certificateTemplateId: profile.certificateTemplateId,
estConfig:
profile.enrollmentType === "est"
profile.enrollmentType === EnrollmentType.EST
? {
disableBootstrapCaValidation:
profile.estConfig?.disableBootstrapCaValidation || false,
@@ -231,19 +374,19 @@ export const CreateProfileModal = ({
}
: undefined,
apiConfig:
profile.enrollmentType === "api"
profile.enrollmentType === EnrollmentType.API
? {
autoRenew: profile.apiConfig?.autoRenew || false,
renewBeforeDays: profile.apiConfig?.renewBeforeDays || 30
}
: undefined,
acmeConfig: profile.enrollmentType === "acme" ? {} : undefined
acmeConfig: profile.enrollmentType === EnrollmentType.ACME ? {} : undefined
}
: {
slug: "",
description: "",
enrollmentType: "api",
issuerType: "ca",
enrollmentType: EnrollmentType.API,
issuerType: IssuerType.CA,
certificateAuthorityId: "",
certificateTemplateId: "",
apiConfig: {
@@ -284,13 +427,13 @@ export const CreateProfileModal = ({
renewBeforeDays: profile.apiConfig?.renewBeforeDays || 30
}
: undefined,
acmeConfig: profile.enrollmentType === "acme" ? {} : undefined
acmeConfig: profile.enrollmentType === EnrollmentType.ACME ? {} : undefined
});
}
}, [isEdit, profile, reset]);
const onFormSubmit = async (data: FormData) => {
if (!isEdit && !subscription?.pkiAcme && data.enrollmentType === "acme") {
if (!isEdit && !subscription?.pkiAcme && data.enrollmentType === EnrollmentType.ACME) {
reset();
onClose();
handlePopUpOpen("upgradePlan", {
@@ -309,11 +452,11 @@ export const CreateProfileModal = ({
issuerType: data.issuerType
};
if (data.enrollmentType === "est" && data.estConfig) {
if (data.enrollmentType === EnrollmentType.EST && data.estConfig) {
updateData.estConfig = data.estConfig;
} else if (data.enrollmentType === "api" && data.apiConfig) {
} else if (data.enrollmentType === EnrollmentType.API && data.apiConfig) {
updateData.apiConfig = data.apiConfig;
} else if (data.enrollmentType === "acme" && data.acmeConfig) {
} else if (data.enrollmentType === EnrollmentType.ACME && data.acmeConfig) {
updateData.acmeConfig = data.acmeConfig;
}
@@ -330,19 +473,21 @@ export const CreateProfileModal = ({
enrollmentType: data.enrollmentType,
issuerType: data.issuerType,
caId:
data.issuerType === "self-signed" ? undefined : data.certificateAuthorityId || undefined,
data.issuerType === IssuerType.SELF_SIGNED
? undefined
: data.certificateAuthorityId || undefined,
certificateTemplateId: data.certificateTemplateId
};
if (data.enrollmentType === "est" && data.estConfig) {
if (data.enrollmentType === EnrollmentType.EST && data.estConfig) {
createData.estConfig = {
passphrase: data.estConfig.passphrase,
caChain: data.estConfig.caChain || undefined,
disableBootstrapCaValidation: data.estConfig.disableBootstrapCaValidation
};
} else if (data.enrollmentType === "api" && data.apiConfig) {
} else if (data.enrollmentType === EnrollmentType.API && data.apiConfig) {
createData.apiConfig = data.apiConfig;
} else if (data.enrollmentType === "acme" && data.acmeConfig) {
} else if (data.enrollmentType === EnrollmentType.ACME && data.acmeConfig) {
createData.acmeConfig = data.acmeConfig;
}
@@ -417,7 +562,7 @@ export const CreateProfileModal = ({
onValueChange={(value) => {
if (value === "self-signed") {
setValue("certificateAuthorityId", "");
setValue("enrollmentType", "api");
setValue("enrollmentType", EnrollmentType.API);
setValue("apiConfig", {
autoRenew: false,
renewBeforeDays: 30
@@ -559,12 +704,12 @@ export const CreateProfileModal = ({
isDisabled={Boolean(isEdit)}
>
<SelectItem value="api">API</SelectItem>
<SelectItem value="est" isDisabled={watchedIssuerType === "self-signed"}>
EST
</SelectItem>
<SelectItem value="acme" isDisabled={watchedIssuerType === "self-signed"}>
ACME
</SelectItem>
{watchedIssuerType !== IssuerType.SELF_SIGNED && (
<SelectItem value="est">EST</SelectItem>
)}
{watchedIssuerType !== IssuerType.SELF_SIGNED && (
<SelectItem value="acme">ACME</SelectItem>
)}
</Select>
</FormControl>
)}

View File

@@ -47,7 +47,6 @@ export const ProfileList = ({
<Tr>
<Th>Name</Th>
<Th>Enrollment Method</Th>
<Th>Issuer Type</Th>
<Th>Issuing CA</Th>
<Th>Certificate Template</Th>
<Th className="w-5" />
@@ -55,7 +54,7 @@ export const ProfileList = ({
</THead>
<TBody>
<Tr>
<Td colSpan={7}>
<Td colSpan={5}>
<EmptyState title="No Project Selected" />
</Td>
</Tr>
@@ -72,17 +71,16 @@ export const ProfileList = ({
<Tr>
<Th>Name</Th>
<Th>Enrollment Method</Th>
<Th>Issuer Type</Th>
<Th>Issuing CA</Th>
<Th>Certificate Template</Th>
<Th className="w-5" />
</Tr>
</THead>
<TBody>
{isLoading && <TableSkeleton columns={6} innerKey="certificate-profiles" />}
{isLoading && <TableSkeleton columns={5} innerKey="certificate-profiles" />}
{!isLoading && (!profiles || profiles.length === 0) && (
<Tr>
<Td colSpan={6}>
<Td colSpan={5}>
<EmptyState title="No Certificate Profiles" />
</Td>
</Tr>

View File

@@ -30,7 +30,7 @@ import {
} from "@app/context/ProjectPermissionContext/types";
import { usePopUp, useToggle } from "@app/hooks";
import { useGetCaById } from "@app/hooks/api/ca/queries";
import { TCertificateProfile } from "@app/hooks/api/certificateProfiles";
import { IssuerType, TCertificateProfile } from "@app/hooks/api/certificateProfiles";
import { useGetCertificateTemplateV2ById } from "@app/hooks/api/certificateTemplates/queries";
import { CertificateIssuanceModal } from "@app/pages/cert-manager/CertificatesPage/components/CertificateIssuanceModal";
@@ -106,20 +106,6 @@ export const ProfileRow = ({
return <Badge variant={variant}>{label}</Badge>;
};
const getIssuerTypeBadge = (issuerType: string) => {
const config = {
ca: { variant: "success" as const, label: "CA" },
"self-signed": { variant: "info" as const, label: "Self-Signed" }
} as const;
const configKey = Object.keys(config).includes(issuerType)
? (issuerType as keyof typeof config)
: "ca";
const { variant, label } = config[configKey];
return <Badge variant={variant}>{label}</Badge>;
};
return (
<Tr key={profile.id} className="h-10 transition-colors duration-100 hover:bg-mineshaft-700">
<Td>
@@ -133,11 +119,10 @@ export const ProfileRow = ({
</div>
</Td>
<Td className="text-start">{getEnrollmentTypeBadge(profile.enrollmentType)}</Td>
<Td className="text-start">{getIssuerTypeBadge(profile.issuerType)}</Td>
<Td className="text-start">
<span className="text-sm text-mineshaft-300">
{profile.issuerType === "self-signed"
? ""
{profile.issuerType === IssuerType.SELF_SIGNED
? "Self-signed"
: caData?.friendlyName || caData?.commonName || profile.caId}
</span>
</Td>