misc: key usages setup

This commit is contained in:
Sheen Capadngan
2024-09-10 21:42:41 +08:00
parent a8fd83652d
commit 1c749c84f2
11 changed files with 199 additions and 20 deletions
@@ -1,3 +1,5 @@
import { CertKeyUsage } from "../certificates/types";
export type TCertificateTemplate = {
id: string;
caId: string;
@@ -8,6 +10,7 @@ export type TCertificateTemplate = {
commonName: string;
subjectAlternativeName: string;
ttl: string;
keyUsages: CertKeyUsage[];
};
export type TCreateCertificateTemplateDTO = {
@@ -18,6 +21,7 @@ export type TCreateCertificateTemplateDTO = {
subjectAlternativeName: string;
ttl: string;
projectId: string;
keyUsages: CertKeyUsage[];
};
export type TUpdateCertificateTemplateDTO = {
@@ -29,6 +33,7 @@ export type TUpdateCertificateTemplateDTO = {
subjectAlternativeName?: string;
ttl?: string;
projectId: string;
keyUsages?: CertKeyUsage[];
};
export type TDeleteCertificateTemplateDTO = {
@@ -23,3 +23,15 @@ export type TRevokeCertDTO = {
serialNumber: string;
revocationReason: string;
};
export enum CertKeyUsage {
DIGITAL_SIGNATURE = "digitalSignature",
KEY_ENCIPHERMENT = "keyEncipherment",
NON_REPUDIATION = "nonRepudiation",
DATA_ENCIPHERMENT = "dataEncipherment",
KEY_AGREEMENT = "keyAgreement",
KEY_CERT_SIGN = "keyCertSign",
CRL_SIGN = "cRLSign",
ENCIPHER_ONLY = "encipherOnly",
DECIPHER_ONLY = "decipherOnly"
}
@@ -7,7 +7,12 @@ import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
Button,
Checkbox,
FormControl,
FormLabel,
Input,
@@ -25,8 +30,10 @@ import {
useGetCertTemplate,
useListWorkspaceCas,
useListWorkspacePkiCollections,
useUpdateCertTemplate} from "@app/hooks/api";
useUpdateCertTemplate
} from "@app/hooks/api";
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
import { CertKeyUsage } from "@app/hooks/api/certificates/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
const validateTemplateRegexField = z
@@ -45,7 +52,18 @@ const schema = z.object({
name: z.string().min(1),
commonName: validateTemplateRegexField,
subjectAlternativeName: validateTemplateRegexField,
ttl: z.string().trim().min(1)
ttl: z.string().trim().min(1),
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()
})
});
export type FormData = z.infer<typeof schema>;
@@ -59,11 +77,23 @@ type Props = {
) => void;
};
const KEY_USAGES_OPTIONS = [
{ value: CertKeyUsage.DIGITAL_SIGNATURE, label: "Digital Signature" },
{ value: CertKeyUsage.KEY_ENCIPHERMENT, label: "Key Encipherment" },
{ value: CertKeyUsage.NON_REPUDIATION, label: "Non Repudiation" },
{ value: CertKeyUsage.DATA_ENCIPHERMENT, label: "Data Encipherment" },
{ value: CertKeyUsage.KEY_AGREEMENT, label: "Key Agreement" },
{ value: CertKeyUsage.KEY_CERT_SIGN, label: "Key Certification Sign" },
{ value: CertKeyUsage.CRL_SIGN, label: "CRL Sign" },
{ value: CertKeyUsage.ENCIPHER_ONLY, label: "Encipher Only" },
{ value: CertKeyUsage.DECIPHER_ONLY, label: "Decipher Only" }
] as const;
export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Props) => {
const { currentWorkspace } = useWorkspace();
const { data: ca } = useGetCaById(caId);
const { data: certTemplate } = useGetCertTemplate(
(popUp?.certificateTemplate?.data as { id: string })?.id || ""
);
@@ -86,7 +116,13 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
reset,
formState: { isSubmitting }
} = useForm<FormData>({
resolver: zodResolver(schema)
resolver: zodResolver(schema),
defaultValues: {
keyUsages: {
[CertKeyUsage.DIGITAL_SIGNATURE]: true,
[CertKeyUsage.KEY_ENCIPHERMENT]: true
}
}
});
useEffect(() => {
@@ -97,14 +133,19 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
commonName: certTemplate.commonName,
subjectAlternativeName: certTemplate.subjectAlternativeName,
collectionId: certTemplate.pkiCollectionId ?? undefined,
ttl: certTemplate.ttl
ttl: certTemplate.ttl,
keyUsages: Object.fromEntries(certTemplate.keyUsages.map((name) => [name, true]))
});
} else {
reset({
caId,
name: "",
commonName: "",
ttl: ""
ttl: "",
keyUsages: {
[CertKeyUsage.DIGITAL_SIGNATURE]: true,
[CertKeyUsage.KEY_ENCIPHERMENT]: true
}
});
}
}, [certTemplate, ca]);
@@ -114,7 +155,8 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
name,
commonName,
subjectAlternativeName,
ttl
ttl,
keyUsages
}: FormData) => {
if (!currentWorkspace?.id) {
return;
@@ -130,7 +172,10 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
name,
commonName,
subjectAlternativeName,
ttl
ttl,
keyUsages: Object.entries(keyUsages)
.filter(([, value]) => value)
.map(([key]) => key as CertKeyUsage)
});
createNotification({
@@ -145,7 +190,10 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
name,
commonName,
subjectAlternativeName,
ttl
ttl,
keyUsages: Object.entries(keyUsages)
.filter(([, value]) => value)
.map(([key]) => key as CertKeyUsage)
});
createNotification({
@@ -332,7 +380,50 @@ export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Pro
</FormControl>
)}
/>
<div className="flex items-center">
<Accordion type="single" collapsible className="w-full">
<AccordionItem value="key-usages" className="data-[state=open]:border-none">
<AccordionTrigger className="h-fit flex-none pl-1 text-sm">
<div className="order-1 ml-3">Key Usages</div>
</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="keyUsages"
render={({ field: { onChange, value }, fieldState: { error } }) => {
return (
<FormControl
label="Key Usages"
errorText={error?.message}
isError={Boolean(error)}
>
<div className="mt-2 mb-7 grid grid-cols-2 gap-2">
{KEY_USAGES_OPTIONS.map(({ label, value: optionValue }) => {
return (
<Checkbox
id={optionValue}
key={optionValue}
className="data-[state=checked]:bg-primary"
isChecked={value[optionValue]}
onCheckedChange={(state) => {
onChange({
...value,
[optionValue]: state
});
}}
>
{label}
</Checkbox>
);
})}
</div>
</FormControl>
);
}}
/>
</AccordionContent>
</AccordionItem>
</Accordion>
<div className="mt-4 flex items-center">
<Button
className="mr-4"
size="sm"