mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-16 23:25:26 +00:00
Transfer cert endpoints to work with serial numbers
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@ type Props = {
|
||||
|
||||
export const CertificateCertModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
const { data } = useGetCertCert(
|
||||
(popUp?.certificateCert?.data as { certId: string })?.certId || ""
|
||||
(popUp?.certificateCert?.data as { serialNumber: string })?.serialNumber || ""
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
+39
-35
@@ -111,41 +111,45 @@ export const CertificateContent = ({
|
||||
<div className="mb-8 flex items-center justify-between rounded-md bg-white/[0.07] p-2 text-base text-gray-400">
|
||||
<p className="mr-4 whitespace-pre-wrap break-all">{certificate}</p>
|
||||
</div>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2>Certificate Chain</h2>
|
||||
<div className="flex">
|
||||
<IconButton
|
||||
ariaLabel="copy icon"
|
||||
colorSchema="secondary"
|
||||
className="group relative"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(certificateChain);
|
||||
setIsCertificateChainCopied.on();
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={isCertificateChainCopied ? faCheck : faCopy} />
|
||||
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
|
||||
Copy
|
||||
</span>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
ariaLabel="copy icon"
|
||||
colorSchema="secondary"
|
||||
className="group relative ml-2"
|
||||
onClick={() => {
|
||||
downloadTxtFile("certificate_chain.txt", certificate);
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faDownload} />
|
||||
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
|
||||
Download
|
||||
</span>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-8 flex items-center justify-between rounded-md bg-white/[0.07] p-2 text-base text-gray-400">
|
||||
<p className="mr-4 whitespace-pre-wrap break-all">{certificateChain}</p>
|
||||
</div>
|
||||
{certificateChain && (
|
||||
<>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h2>Certificate Chain</h2>
|
||||
<div className="flex">
|
||||
<IconButton
|
||||
ariaLabel="copy icon"
|
||||
colorSchema="secondary"
|
||||
className="group relative"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(certificateChain);
|
||||
setIsCertificateChainCopied.on();
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={isCertificateChainCopied ? faCheck : faCopy} />
|
||||
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
|
||||
Copy
|
||||
</span>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
ariaLabel="copy icon"
|
||||
colorSchema="secondary"
|
||||
className="group relative ml-2"
|
||||
onClick={() => {
|
||||
downloadTxtFile("certificate_chain.txt", certificateChain);
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faDownload} />
|
||||
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
|
||||
Download
|
||||
</span>
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-8 flex items-center justify-between rounded-md bg-white/[0.07] p-2 text-base text-gray-400">
|
||||
<p className="mr-4 whitespace-pre-wrap break-all">{certificateChain}</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{privateKey && (
|
||||
<>
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
|
||||
+3
-8
@@ -15,12 +15,7 @@ import {
|
||||
SelectItem
|
||||
} from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import {
|
||||
CaStatus,
|
||||
useCreateCertificate,
|
||||
useGetCertById,
|
||||
useListWorkspaceCas
|
||||
} from "@app/hooks/api";
|
||||
import { CaStatus, useCreateCertificate, useGetCert, useListWorkspaceCas } from "@app/hooks/api";
|
||||
import { caTypeToNameMap } from "@app/hooks/api/ca/constants";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
@@ -60,8 +55,8 @@ type TCertificateDetails = {
|
||||
export const CertificateModal = ({ popUp, handlePopUpToggle }: Props) => {
|
||||
const [certificateDetails, setCertificateDetails] = useState<TCertificateDetails | null>(null);
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { data: cert } = useGetCertById(
|
||||
(popUp?.certificate?.data as { certId: string })?.certId || ""
|
||||
const { data: cert } = useGetCert(
|
||||
(popUp?.certificate?.data as { serialNumber: string })?.serialNumber || ""
|
||||
);
|
||||
|
||||
const { data: cas } = useListWorkspaceCas({
|
||||
|
||||
+61
-18
@@ -2,9 +2,10 @@ import { faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { ProjectPermissionCan } from "@app/components/permissions";
|
||||
import { Button, DeleteActionModal } from "@app/components/v2";
|
||||
import { useWorkspace } from "@app/context";
|
||||
import { useDeleteCert } from "@app/hooks/api";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||
import { useDeleteCert, useRevokeCert } from "@app/hooks/api";
|
||||
import { usePopUp } from "@app/hooks/usePopUp";
|
||||
|
||||
import { CertificateCertModal } from "./CertificateCertModal";
|
||||
@@ -14,18 +15,20 @@ import { CertificatesTable } from "./CertificatesTable";
|
||||
export const CertificatesSection = () => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { mutateAsync: deleteCert } = useDeleteCert();
|
||||
const { mutateAsync: revokeCert } = useRevokeCert();
|
||||
|
||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||
"certificate",
|
||||
"certificateCert",
|
||||
"deleteCertificate"
|
||||
"deleteCertificate",
|
||||
"revokeCertificate"
|
||||
] as const);
|
||||
|
||||
const onRemoveCertificateSubmit = async (certId: string) => {
|
||||
const onRemoveCertificateSubmit = async (serialNumber: string) => {
|
||||
try {
|
||||
if (!currentWorkspace?.slug) return;
|
||||
|
||||
await deleteCert({ certId, projectSlug: currentWorkspace.slug });
|
||||
await deleteCert({ serialNumber, projectSlug: currentWorkspace.slug });
|
||||
|
||||
await createNotification({
|
||||
text: "Successfully deleted certificate",
|
||||
@@ -42,23 +45,47 @@ export const CertificatesSection = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const onRevokeCertificateSubmit = async (serialNumber: string) => {
|
||||
try {
|
||||
if (!currentWorkspace?.slug) return;
|
||||
|
||||
await revokeCert({ serialNumber, projectSlug: currentWorkspace.slug });
|
||||
|
||||
await createNotification({
|
||||
text: "Successfully revoked certificate",
|
||||
type: "success"
|
||||
});
|
||||
|
||||
handlePopUpClose("revokeCertificate");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
createNotification({
|
||||
text: "Failed to revoke certificate",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-4 flex justify-between">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">Certificates</p>
|
||||
{/* <OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
|
||||
{(isAllowed) => ( */}
|
||||
<Button
|
||||
colorSchema="primary"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => handlePopUpOpen("certificate")}
|
||||
// isDisabled={!isAllowed}
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Create}
|
||||
a={ProjectPermissionSub.Certificates}
|
||||
>
|
||||
Issue Certificate
|
||||
</Button>
|
||||
{/* )} */}
|
||||
{/* </OrgPermissionCan> */}
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
colorSchema="primary"
|
||||
type="submit"
|
||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||
onClick={() => handlePopUpOpen("certificate")}
|
||||
isDisabled={!isAllowed}
|
||||
>
|
||||
Issue Certificate
|
||||
</Button>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
</div>
|
||||
<CertificatesTable handlePopUpOpen={handlePopUpOpen} />
|
||||
<CertificateModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
|
||||
@@ -71,7 +98,23 @@ export const CertificatesSection = () => {
|
||||
onChange={(isOpen) => handlePopUpToggle("deleteCertificate", isOpen)}
|
||||
deleteKey="confirm"
|
||||
onDeleteApproved={() =>
|
||||
onRemoveCertificateSubmit((popUp?.deleteCertificate?.data as { certId: string })?.certId)
|
||||
onRemoveCertificateSubmit(
|
||||
(popUp?.deleteCertificate?.data as { serialNumber: string })?.serialNumber
|
||||
)
|
||||
}
|
||||
/>
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.revokeCertificate.isOpen}
|
||||
title={`Are you sure want to revoke the certificate ${
|
||||
(popUp?.revokeCertificate?.data as { commonName: string })?.commonName || ""
|
||||
} from the project?`}
|
||||
subTitle="This action is irreversible and will add the certificate to the CRL"
|
||||
onChange={(isOpen) => handlePopUpToggle("revokeCertificate", isOpen)}
|
||||
deleteKey="confirm"
|
||||
onDeleteApproved={() =>
|
||||
onRevokeCertificateSubmit(
|
||||
(popUp?.revokeCertificate?.data as { serialNumber: string }).serialNumber
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+34
-8
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
faBan,
|
||||
faCertificate,
|
||||
faEllipsis,
|
||||
faEye,
|
||||
@@ -24,16 +25,20 @@ import {
|
||||
Th,
|
||||
THead,
|
||||
Tooltip,
|
||||
Tr} from "@app/components/v2";
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
|
||||
import { useListWorkspaceCertificates } from "@app/hooks/api";
|
||||
import { certStatusToNameMap } from "@app/hooks/api/certificates/constants";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
type Props = {
|
||||
handlePopUpOpen: (
|
||||
popUpName: keyof UsePopUpState<["certificate", "deleteCertificate", "certificateCert"]>,
|
||||
popUpName: keyof UsePopUpState<
|
||||
["certificate", "deleteCertificate", "revokeCertificate", "certificateCert"]
|
||||
>,
|
||||
data?: {
|
||||
certId?: string;
|
||||
serialNumber?: string;
|
||||
commonName?: string;
|
||||
}
|
||||
) => void;
|
||||
@@ -48,8 +53,8 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
<Table>
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th>Certificate ID</Th>
|
||||
<Th>Common Name</Th>
|
||||
<Th>Status</Th>
|
||||
<Th>Valid Until</Th>
|
||||
<Th />
|
||||
</Tr>
|
||||
@@ -62,8 +67,8 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
data.map((certificate) => {
|
||||
return (
|
||||
<Tr className="h-10" key={`certificate-${certificate.id}`}>
|
||||
<Td>{certificate.id}</Td>
|
||||
<Td>{certificate.commonName}</Td>
|
||||
<Td>{certStatusToNameMap[certificate.status]}</Td>
|
||||
<Td>
|
||||
{certificate.notAfter
|
||||
? format(new Date(certificate.notAfter), "yyyy-MM-dd")
|
||||
@@ -90,7 +95,7 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
)}
|
||||
onClick={async () =>
|
||||
handlePopUpOpen("certificateCert", {
|
||||
certId: certificate.id
|
||||
serialNumber: certificate.serialNumber
|
||||
})
|
||||
}
|
||||
disabled={!isAllowed}
|
||||
@@ -111,7 +116,7 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
)}
|
||||
onClick={async () =>
|
||||
handlePopUpOpen("certificate", {
|
||||
certId: certificate.id
|
||||
serialNumber: certificate.serialNumber
|
||||
})
|
||||
}
|
||||
disabled={!isAllowed}
|
||||
@@ -121,6 +126,27 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={ProjectPermissionSub.Certificates}
|
||||
>
|
||||
{(isAllowed) => (
|
||||
<DropdownMenuItem
|
||||
className={twMerge(
|
||||
!isAllowed && "pointer-events-none cursor-not-allowed opacity-50"
|
||||
)}
|
||||
onClick={async () =>
|
||||
handlePopUpOpen("revokeCertificate", {
|
||||
serialNumber: certificate.serialNumber
|
||||
})
|
||||
}
|
||||
disabled={!isAllowed}
|
||||
icon={<FontAwesomeIcon icon={faBan} />}
|
||||
>
|
||||
Revoke Certificate
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</ProjectPermissionCan>
|
||||
<ProjectPermissionCan
|
||||
I={ProjectPermissionActions.Delete}
|
||||
a={ProjectPermissionSub.Certificates}
|
||||
@@ -132,7 +158,7 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
|
||||
)}
|
||||
onClick={async () =>
|
||||
handlePopUpOpen("deleteCertificate", {
|
||||
certId: certificate.id,
|
||||
serialNumber: certificate.serialNumber,
|
||||
commonName: certificate.commonName
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user