mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 07:28:51 +00:00
logging, finalizing some functions, and other tweaks
This commit is contained in:
@@ -209,6 +209,7 @@ export enum EventType {
|
||||
IMPORT_CA_CERT = "import-certificate-authority-cert",
|
||||
GET_CA_CRLS = "get-certificate-authority-crls",
|
||||
ISSUE_CERT = "issue-cert",
|
||||
IMPORT_CERT = "import-cert",
|
||||
SIGN_CERT = "sign-cert",
|
||||
GET_CA_CERTIFICATE_TEMPLATES = "get-ca-certificate-templates",
|
||||
GET_CERT = "get-cert",
|
||||
@@ -1666,6 +1667,15 @@ interface IssueCert {
|
||||
};
|
||||
}
|
||||
|
||||
interface ImportCert {
|
||||
type: EventType.IMPORT_CERT;
|
||||
metadata: {
|
||||
certId: string;
|
||||
cn: string;
|
||||
serialNumber: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface SignCert {
|
||||
type: EventType.SIGN_CERT;
|
||||
metadata: {
|
||||
@@ -2685,6 +2695,7 @@ export type Event =
|
||||
| ImportCaCert
|
||||
| GetCaCrls
|
||||
| IssueCert
|
||||
| ImportCert
|
||||
| SignCert
|
||||
| GetCaCertificateTemplates
|
||||
| GetCert
|
||||
|
||||
@@ -805,7 +805,9 @@ export const registerRoutes = async (
|
||||
certificateAuthoritySecretDAL,
|
||||
projectDAL,
|
||||
kmsService,
|
||||
permissionService
|
||||
permissionService,
|
||||
pkiCollectionDAL,
|
||||
pkiCollectionItemDAL
|
||||
});
|
||||
|
||||
const certificateAuthorityQueue = certificateAuthorityQueueFactory({
|
||||
|
||||
@@ -192,8 +192,8 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
||||
projectSlug: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.projectSlug),
|
||||
|
||||
certificatePem: z.string().trim().min(1).describe(CERTIFICATES.IMPORT.certificatePem),
|
||||
privateKeyPem: z.string().trim().optional().describe(CERTIFICATES.IMPORT.privateKeyPem),
|
||||
chainPem: z.string().trim().optional().describe(CERTIFICATES.IMPORT.chainPem),
|
||||
privateKeyPem: z.string().trim().describe(CERTIFICATES.IMPORT.privateKeyPem),
|
||||
chainPem: z.string().trim().describe(CERTIFICATES.IMPORT.chainPem),
|
||||
|
||||
friendlyName: z.string().trim().optional().describe(CERTIFICATES.IMPORT.friendlyName),
|
||||
pkiCollectionId: z.string().trim().optional().describe(CERTIFICATES.IMPORT.pkiCollectionId)
|
||||
@@ -201,46 +201,35 @@ export const registerCertRouter = async (server: FastifyZodProvider) => {
|
||||
response: {
|
||||
200: z.object({
|
||||
certificate: z.string().trim().describe(CERTIFICATES.IMPORT.certificate),
|
||||
certificateChain: z.string().trim().optional().describe(CERTIFICATES.IMPORT.certificateChain),
|
||||
privateKey: z.string().trim().optional().describe(CERTIFICATES.IMPORT.privateKey),
|
||||
certificateChain: z.string().trim().describe(CERTIFICATES.IMPORT.certificateChain),
|
||||
privateKey: z.string().trim().describe(CERTIFICATES.IMPORT.privateKey),
|
||||
serialNumber: z.string().trim().describe(CERTIFICATES.IMPORT.serialNumber)
|
||||
})
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
const { certificate, certificateChain, privateKey, serialNumber } = await server.services.certificate.importCert({
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
actorOrgId: req.permission.orgId,
|
||||
...req.body
|
||||
const { certificate, certificateChain, privateKey, serialNumber, cert } =
|
||||
await server.services.certificate.importCert({
|
||||
actor: req.permission.type,
|
||||
actorId: req.permission.id,
|
||||
actorAuthMethod: req.permission.authMethod,
|
||||
actorOrgId: req.permission.orgId,
|
||||
...req.body
|
||||
});
|
||||
|
||||
await server.services.auditLog.createAuditLog({
|
||||
...req.auditLogInfo,
|
||||
projectId: cert.projectId,
|
||||
event: {
|
||||
type: EventType.IMPORT_CERT,
|
||||
metadata: {
|
||||
certId: cert.id,
|
||||
cn: cert.commonName,
|
||||
serialNumber
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// TODO(andrey): Add logs
|
||||
// await server.services.auditLog.createAuditLog({
|
||||
// ...req.auditLogInfo,
|
||||
// projectId: ca.projectId,
|
||||
// event: {
|
||||
// type: EventType.ISSUE_CERT,
|
||||
// metadata: {
|
||||
// caId: ca.id,
|
||||
// dn: ca.dn,
|
||||
// serialNumber
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
|
||||
// await server.services.telemetry.sendPostHogEvents({
|
||||
// event: PostHogEventTypes.IssueCert,
|
||||
// distinctId: getTelemetryDistinctId(req),
|
||||
// properties: {
|
||||
// caId: req.body.caId,
|
||||
// certificateTemplateId: req.body.certificateTemplateId,
|
||||
// commonName: req.body.commonName,
|
||||
// ...req.auditLogInfo
|
||||
// }
|
||||
// });
|
||||
|
||||
return {
|
||||
certificate,
|
||||
certificateChain,
|
||||
|
||||
@@ -1389,7 +1389,7 @@ export const certificateAuthorityServiceFactory = ({
|
||||
notAfter: notAfterDate,
|
||||
keyUsages: selectedKeyUsages,
|
||||
extendedKeyUsages: selectedExtendedKeyUsages,
|
||||
projectId: ca.projectId
|
||||
projectId: (ca as TCertificateAuthorities).projectId
|
||||
},
|
||||
tx
|
||||
);
|
||||
@@ -1782,7 +1782,7 @@ export const certificateAuthorityServiceFactory = ({
|
||||
notAfter: notAfterDate,
|
||||
keyUsages: selectedKeyUsages,
|
||||
extendedKeyUsages: selectedExtendedKeyUsages,
|
||||
projectId: ca.projectId
|
||||
projectId: (ca as TCertificateAuthorities).projectId
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
@@ -46,3 +46,6 @@ export const constructPemChainFromCerts = (certificates: x509.X509Certificate[])
|
||||
.map((cert) => cert.toString("pem"))
|
||||
.join("\n")
|
||||
.trim();
|
||||
|
||||
export const splitPemChain = (pemText: string) =>
|
||||
pemText.match(/-----BEGIN CERTIFICATE-----[^-]+-----END CERTIFICATE-----/g) || [];
|
||||
|
||||
@@ -19,8 +19,11 @@ import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||
import { getProjectKmsCertificateKeyId } from "@app/services/project/project-fns";
|
||||
|
||||
import { getCaCertChain, rebuildCaCrl } from "../certificate-authority/certificate-authority-fns";
|
||||
import { revocationReasonToCrlCode } from "./certificate-fns";
|
||||
import { revocationReasonToCrlCode, splitPemChain } from "./certificate-fns";
|
||||
import {
|
||||
CertExtendedKeyUsage,
|
||||
CertExtendedKeyUsageOIDToName,
|
||||
CertKeyUsage,
|
||||
CertStatus,
|
||||
TDeleteCertDTO,
|
||||
TGetCertBodyDTO,
|
||||
@@ -273,46 +276,54 @@ export const certificateServiceFactory = ({
|
||||
}
|
||||
|
||||
// Parse the certificate
|
||||
const certObj = new x509.X509Certificate(certificatePem);
|
||||
const leafCert = new x509.X509Certificate(certificatePem);
|
||||
|
||||
// Verify the certificate chain
|
||||
if (chainPem) {
|
||||
const chainCert = new x509.X509Certificate(chainPem);
|
||||
if (!(await certObj.verify({ publicKey: chainCert.publicKey }))) {
|
||||
throw new BadRequestError({ message: "Certificate chain verification failed" });
|
||||
}
|
||||
const chainCerts = splitPemChain(chainPem).map((pem) => new x509.X509Certificate(pem));
|
||||
if (chainCerts.length === 0) {
|
||||
throw new BadRequestError({
|
||||
message: "Certificate chain must contain at least one issuer certificate"
|
||||
});
|
||||
}
|
||||
|
||||
// If private key provided, verify it matches the certificate
|
||||
if (privateKeyPem) {
|
||||
try {
|
||||
const message = Buffer.from("certificate-verification-test");
|
||||
const chainValidationPromises = chainCerts.map((issuerCert) =>
|
||||
leafCert.verify({ publicKey: issuerCert.publicKey }).catch(() => false)
|
||||
);
|
||||
|
||||
const privateKey = createPrivateKey(privateKeyPem);
|
||||
const publicKey = createPublicKey(certificatePem);
|
||||
const results = await Promise.all(chainValidationPromises);
|
||||
|
||||
const signature = sign(null, message, privateKey);
|
||||
const isValid = verify(null, message, publicKey, signature);
|
||||
if (!results.some((result) => result === true)) {
|
||||
throw new BadRequestError({ message: "Certificate chain verification failed" });
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
throw new BadRequestError({ message: "Private key does not match certificate" });
|
||||
}
|
||||
} catch (err) {
|
||||
throw new BadRequestError({ message: "Invalid private key format" });
|
||||
// Verify private key matches the certificate
|
||||
try {
|
||||
const message = Buffer.from("certificate-verification-test");
|
||||
|
||||
const privateKey = createPrivateKey(privateKeyPem);
|
||||
const publicKey = createPublicKey(certificatePem);
|
||||
|
||||
const signature = sign(null, message, privateKey);
|
||||
const isValid = verify(null, message, publicKey, signature);
|
||||
|
||||
if (!isValid) {
|
||||
throw new BadRequestError({ message: "Private key does not match certificate" });
|
||||
}
|
||||
} catch (err) {
|
||||
throw new BadRequestError({ message: "Invalid private key format" });
|
||||
}
|
||||
|
||||
// Get certificate attributes
|
||||
const commonName = Array.from(certObj.subjectName.getField("CN")?.values() || [])[0] || "";
|
||||
const commonName = Array.from(leafCert.subjectName.getField("CN")?.values() || [])[0] || "";
|
||||
|
||||
let altNames: undefined | string;
|
||||
const sanExtension = certObj.extensions.find((ext) => ext.type === "2.5.29.17");
|
||||
const sanExtension = leafCert.extensions.find((ext) => ext.type === "2.5.29.17");
|
||||
if (sanExtension) {
|
||||
const sanNames = new x509.GeneralNames(sanExtension.value);
|
||||
altNames = sanNames.items.map((name) => name.value).join(", ");
|
||||
}
|
||||
|
||||
const { serialNumber, notBefore, notAfter } = certObj;
|
||||
const { serialNumber, notBefore, notAfter } = leafCert;
|
||||
|
||||
// Encrypt certificate for storage
|
||||
const certificateManagerKeyId = await getProjectKmsCertificateKeyId({
|
||||
@@ -328,50 +339,83 @@ export const certificateServiceFactory = ({
|
||||
plainText: Buffer.from(certificatePem)
|
||||
});
|
||||
|
||||
await certificateDAL.transaction(async (tx) => {
|
||||
const cert = await certificateDAL.create(
|
||||
{
|
||||
status: CertStatus.ACTIVE,
|
||||
friendlyName: friendlyName || commonName,
|
||||
commonName,
|
||||
altNames,
|
||||
serialNumber,
|
||||
notBefore,
|
||||
notAfter,
|
||||
projectId
|
||||
// TODO(andrey): Add keyUsages and extendedKeyUsages
|
||||
// keyUsages,
|
||||
// extendedKeyUsages
|
||||
},
|
||||
tx
|
||||
);
|
||||
// Extract Key Usage
|
||||
const keyUsagesExt = leafCert.getExtension("2.5.29.15") as x509.KeyUsagesExtension;
|
||||
|
||||
await certificateBodyDAL.create(
|
||||
{
|
||||
certId: cert.id,
|
||||
encryptedCertificate
|
||||
},
|
||||
tx
|
||||
let keyUsages: CertKeyUsage[] = [];
|
||||
if (keyUsagesExt) {
|
||||
keyUsages = Object.values(CertKeyUsage).filter(
|
||||
// eslint-disable-next-line no-bitwise
|
||||
(keyUsage) => (x509.KeyUsageFlags[keyUsage] & keyUsagesExt.usages) !== 0
|
||||
);
|
||||
}
|
||||
|
||||
if (collectionId) {
|
||||
await pkiCollectionItemDAL.create(
|
||||
// Extract Extended Key Usage
|
||||
const extKeyUsageExt = leafCert.getExtension("2.5.29.37") as x509.ExtendedKeyUsageExtension;
|
||||
let extendedKeyUsages: CertExtendedKeyUsage[] = [];
|
||||
if (extKeyUsageExt) {
|
||||
extendedKeyUsages = extKeyUsageExt.usages.map((ekuOid) => CertExtendedKeyUsageOIDToName[ekuOid as string]);
|
||||
}
|
||||
|
||||
const cert = await certificateDAL.transaction(async (tx) => {
|
||||
try {
|
||||
const txCert = await certificateDAL.create(
|
||||
{
|
||||
pkiCollectionId: collectionId,
|
||||
certId: cert.id
|
||||
status: CertStatus.ACTIVE,
|
||||
friendlyName: friendlyName || commonName,
|
||||
commonName,
|
||||
altNames,
|
||||
serialNumber,
|
||||
notBefore,
|
||||
notAfter,
|
||||
projectId,
|
||||
keyUsages,
|
||||
extendedKeyUsages
|
||||
},
|
||||
tx
|
||||
);
|
||||
}
|
||||
|
||||
return cert;
|
||||
await certificateBodyDAL.create(
|
||||
{
|
||||
certId: txCert.id,
|
||||
encryptedCertificate
|
||||
},
|
||||
tx
|
||||
);
|
||||
|
||||
if (collectionId) {
|
||||
await pkiCollectionItemDAL.create(
|
||||
{
|
||||
pkiCollectionId: collectionId,
|
||||
certId: txCert.id
|
||||
},
|
||||
tx
|
||||
);
|
||||
}
|
||||
|
||||
return txCert;
|
||||
} catch (error: unknown) {
|
||||
if (
|
||||
typeof error === "object" &&
|
||||
error !== null &&
|
||||
"error" in error &&
|
||||
error.error &&
|
||||
typeof error.error === "object" &&
|
||||
"code" in error.error &&
|
||||
error.error.code === "23505"
|
||||
) {
|
||||
throw new BadRequestError({ message: "Certificate serial already exists in your project" });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
certificate: certificatePem,
|
||||
certificateChain: chainPem,
|
||||
privateKey: privateKeyPem,
|
||||
serialNumber
|
||||
serialNumber,
|
||||
cert
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -81,6 +81,6 @@ export type TImportCertDTO = {
|
||||
pkiCollectionId?: string;
|
||||
|
||||
certificatePem: string;
|
||||
privateKeyPem?: string;
|
||||
chainPem?: string;
|
||||
privateKeyPem: string;
|
||||
chainPem: string;
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
@@ -269,14 +269,8 @@ export const pkiCollectionServiceFactory = ({
|
||||
});
|
||||
if (isCertAdded) throw new BadRequestError({ message: "Certificate already part of the PKI collection" });
|
||||
|
||||
// validate that there exists a certificate in same project as PKI collection
|
||||
const cas = await certificateAuthorityDAL.find({ projectId: pkiCollection.projectId });
|
||||
|
||||
// TODO: consider making this more efficient
|
||||
const [certificate] = await certificateDAL.find({
|
||||
$in: {
|
||||
caId: cas.map((ca) => ca.id)
|
||||
},
|
||||
projectId: pkiCollection.projectId,
|
||||
id: itemId
|
||||
});
|
||||
if (!certificate) throw new NotFoundError({ message: `Certificate with ID '${itemId}' not found` });
|
||||
|
||||
@@ -929,13 +929,9 @@ export const projectServiceFactory = ({
|
||||
|
||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Certificates);
|
||||
|
||||
const cas = await certificateAuthorityDAL.find({ projectId });
|
||||
|
||||
const certificates = await certificateDAL.find(
|
||||
{
|
||||
$in: {
|
||||
caId: cas.map((ca) => ca.id)
|
||||
},
|
||||
projectId,
|
||||
...(friendlyName && { friendlyName }),
|
||||
...(commonName && { commonName })
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import { ProjectType, SecretsV2Schema, SecretType, TableName, TSecretsV2, TSecre
|
||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||
import { getConfig } from "@app/lib/config/env";
|
||||
import { generateCacheKeyFromData } from "@app/lib/crypto/cache";
|
||||
import { applyJitter } from "@app/lib/dates";
|
||||
import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors";
|
||||
import {
|
||||
buildFindFilter,
|
||||
@@ -22,7 +23,6 @@ import type {
|
||||
TFindSecretsByFolderIdsFilter,
|
||||
TGetSecretsDTO
|
||||
} from "@app/services/secret-v2-bridge/secret-v2-bridge-types";
|
||||
import { applyJitter } from "@app/lib/dates";
|
||||
|
||||
export const SecretServiceCacheKeys = {
|
||||
get productKey() {
|
||||
|
||||
@@ -68,6 +68,7 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
||||
[EventType.IMPORT_CA_CERT]: "Import CA certificate",
|
||||
[EventType.GET_CA_CRL]: "Get CA CRL",
|
||||
[EventType.ISSUE_CERT]: "Issue certificate",
|
||||
[EventType.IMPORT_CERT]: "Import certificate",
|
||||
[EventType.GET_CERT]: "Get certificate",
|
||||
[EventType.DELETE_CERT]: "Delete certificate",
|
||||
[EventType.REVOKE_CERT]: "Revoke certificate",
|
||||
|
||||
@@ -74,6 +74,7 @@ export enum EventType {
|
||||
IMPORT_CA_CERT = "import-certificate-authority-cert",
|
||||
GET_CA_CRL = "get-certificate-authority-crl",
|
||||
ISSUE_CERT = "issue-cert",
|
||||
IMPORT_CERT = "import-cert",
|
||||
GET_CERT = "get-cert",
|
||||
DELETE_CERT = "delete-cert",
|
||||
REVOKE_CERT = "revoke-cert",
|
||||
|
||||
@@ -582,6 +582,14 @@ interface IssueCert {
|
||||
serialNumber: string;
|
||||
};
|
||||
}
|
||||
interface ImportCert {
|
||||
type: EventType.IMPORT_CERT;
|
||||
metadata: {
|
||||
certId: string;
|
||||
cn: string;
|
||||
serialNumber: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface GetCert {
|
||||
type: EventType.GET_CERT;
|
||||
@@ -874,6 +882,7 @@ export type Event =
|
||||
| ImportCaCert
|
||||
| GetCaCrl
|
||||
| IssueCert
|
||||
| ImportCert
|
||||
| GetCert
|
||||
| DeleteCert
|
||||
| RevokeCert
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { useDeleteCert, useRevokeCert, useImportCertificate } from "./mutations";
|
||||
export { useDeleteCert, useImportCertificate, useRevokeCert } from "./mutations";
|
||||
export { useGetCert, useGetCertBody } from "./queries";
|
||||
|
||||
@@ -30,17 +30,15 @@ export type TImportCertificateDTO = {
|
||||
projectSlug: string;
|
||||
|
||||
certificatePem: string;
|
||||
privateKeyPem?: string;
|
||||
chainPem?: string;
|
||||
privateKeyPem: string;
|
||||
chainPem: string;
|
||||
|
||||
pkiCollectionId?: string;
|
||||
friendlyName?: string;
|
||||
};
|
||||
|
||||
// TODO(andrey): Change this
|
||||
export type TImportCertificateResponse = {
|
||||
certificate: string;
|
||||
issuingCertificate: string;
|
||||
certificateChain: string;
|
||||
privateKey: string;
|
||||
serialNumber: string;
|
||||
|
||||
@@ -13,9 +13,9 @@ import {
|
||||
TBreadcrumbFormat
|
||||
} from "@app/components/v2";
|
||||
import {
|
||||
useProjectPermission,
|
||||
ProjectPermissionActions,
|
||||
ProjectPermissionSub,
|
||||
useProjectPermission,
|
||||
useSubscription,
|
||||
useWorkspace
|
||||
} from "@app/context";
|
||||
|
||||
+29
-52
@@ -15,43 +15,18 @@ import {
|
||||
TextArea
|
||||
} from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { useImportCertificate, useGetCert, useListWorkspacePkiCollections } from "@app/hooks/api";
|
||||
import { useGetCert, useImportCertificate, useListWorkspacePkiCollections } from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
import { CertificateContent } from "./CertificateContent";
|
||||
|
||||
const schema = z.object({
|
||||
certificatePem: z.string().trim().min(1, "Certificate PEM is required"),
|
||||
privateKeyPem: z.string().trim().optional(),
|
||||
chainPem: z.string().trim().optional(),
|
||||
privateKeyPem: z.string().trim(),
|
||||
chainPem: z.string().trim(),
|
||||
|
||||
friendlyName: z.string(),
|
||||
collectionId: z.string().optional()
|
||||
|
||||
// Can be added as override fields in the future | Also edit /frontend/src/hooks/api/ca/types.ts
|
||||
// commonName: z.string().trim().min(1),
|
||||
// altNames: z.string(),
|
||||
|
||||
// Can be added as override fields in the future | Also edit /frontend/src/hooks/api/ca/types.ts
|
||||
// keyUsages: z.object({
|
||||
// [CertKeyUsage.DIGITAL_SIGNATURE]: z.boolean().optional(),
|
||||
// [CertKeyUsage.KEY_ENCIPHERMENT]: z.boolean().optional(),
|
||||
// [CertKeyUsage.NON_REPUDIATION]: z.boolean().optional(),
|
||||
// [CertKeyUsage.DATA_ENCIPHERMENT]: z.boolean().optional(),
|
||||
// [CertKeyUsage.KEY_AGREEMENT]: z.boolean().optional(),
|
||||
// [CertKeyUsage.KEY_CERT_SIGN]: z.boolean().optional(),
|
||||
// [CertKeyUsage.CRL_SIGN]: z.boolean().optional(),
|
||||
// [CertKeyUsage.ENCIPHER_ONLY]: z.boolean().optional(),
|
||||
// [CertKeyUsage.DECIPHER_ONLY]: z.boolean().optional()
|
||||
// }),
|
||||
// extendedKeyUsages: z.object({
|
||||
// [CertExtendedKeyUsage.CLIENT_AUTH]: z.boolean().optional(),
|
||||
// [CertExtendedKeyUsage.CODE_SIGNING]: z.boolean().optional(),
|
||||
// [CertExtendedKeyUsage.EMAIL_PROTECTION]: z.boolean().optional(),
|
||||
// [CertExtendedKeyUsage.OCSP_SIGNING]: z.boolean().optional(),
|
||||
// [CertExtendedKeyUsage.SERVER_AUTH]: z.boolean().optional(),
|
||||
// [CertExtendedKeyUsage.TIMESTAMPING]: z.boolean().optional()
|
||||
// })
|
||||
});
|
||||
|
||||
export type FormData = z.infer<typeof schema>;
|
||||
@@ -195,33 +170,14 @@ export const CertificateImportModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
name="certificatePem"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Certificate PEM"
|
||||
label="Leaf Certificate PEM"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
isRequired
|
||||
errorText={error?.message}
|
||||
>
|
||||
<TextArea
|
||||
{...field}
|
||||
placeholder="TODO(andrey): Pem placeholder"
|
||||
isDisabled={Boolean(cert)}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="chainPem"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Certificate Chain PEM"
|
||||
isError={Boolean(error)}
|
||||
isOptional
|
||||
errorText={error?.message}
|
||||
>
|
||||
<TextArea
|
||||
{...field}
|
||||
placeholder="TODO(andrey): Pem placeholder"
|
||||
placeholder={"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"}
|
||||
isDisabled={Boolean(cert)}
|
||||
/>
|
||||
</FormControl>
|
||||
@@ -235,12 +191,33 @@ export const CertificateImportModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
<FormControl
|
||||
label="Private Key PEM"
|
||||
isError={Boolean(error)}
|
||||
isOptional
|
||||
errorText={error?.message}
|
||||
isRequired
|
||||
>
|
||||
<TextArea
|
||||
{...field}
|
||||
placeholder="TODO(andrey): Pem placeholder"
|
||||
placeholder={
|
||||
"-----BEGIN EC PRIVATE KEY-----\n...\n-----END EC PRIVATE KEY-----"
|
||||
}
|
||||
isDisabled={Boolean(cert)}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
control={control}
|
||||
defaultValue=""
|
||||
name="chainPem"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Certificate Chain PEM"
|
||||
isError={Boolean(error)}
|
||||
errorText={error?.message}
|
||||
isRequired
|
||||
>
|
||||
<TextArea
|
||||
{...field}
|
||||
placeholder={"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"}
|
||||
isDisabled={Boolean(cert)}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@@ -9,10 +9,10 @@ import { useDeleteCert } from "@app/hooks/api";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
|
||||
import { CertificateCertModal } from "./CertificateCertModal";
|
||||
import { CertificateImportModal } from "./CertificateImportModal";
|
||||
import { CertificateModal } from "./CertificateModal";
|
||||
import { CertificateRevocationModal } from "./CertificateRevocationModal";
|
||||
import { CertificatesTable } from "./CertificatesTable";
|
||||
import { CertificateImportModal } from "./CertificateImportModal";
|
||||
|
||||
export const CertificatesSection = () => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
|
||||
Reference in New Issue
Block a user