diff --git a/frontend/interfaces/integration.ts b/frontend/interfaces/integration.ts
index 891aba0a54..1dbd911c2a 100644
--- a/frontend/interfaces/integration.ts
+++ b/frontend/interfaces/integration.ts
@@ -41,6 +41,33 @@ export interface ICertificatesIntegrationCustomSCEP {
challenge: string;
}
+export const isNDESCertIntegration = (
+ integration: ICertificateIntegration
+): integration is ICertificatesIntegrationNDES => {
+ return (
+ "admin_url" in integration &&
+ "username" in integration &&
+ "password" in integration
+ );
+};
+
+export const isDigicertCertIntegration = (
+ integration: ICertificateIntegration
+): integration is ICertificatesIntegrationDigicert => {
+ return (
+ "profile_id" in integration &&
+ "certificate_common_name" in integration &&
+ "certificate_user_principal_names" in integration &&
+ "certificate_seat_id" in integration
+ );
+};
+
+export const isCustomSCEPCertIntegration = (
+ integration: ICertificateIntegration
+): integration is ICertificatesIntegrationCustomSCEP => {
+ return "id" in integration && "challenge" in integration;
+};
+
export type ICertificateAuthorityType = "ndes" | "digicert" | "custom";
/** all the types of certificate integrations */
diff --git a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/CertificateAuthorities.tsx b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/CertificateAuthorities.tsx
index 4145346f9f..d74a2cd4fd 100644
--- a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/CertificateAuthorities.tsx
+++ b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/CertificateAuthorities.tsx
@@ -17,6 +17,7 @@ import {
import AddCertAuthorityCard from "./components/AddCertAuthorityCard";
import DeleteCertificateAuthorityModal from "./components/DeleteCertificateAuthorityModal";
import AddCertAuthorityModal from "./components/AddCertAuthorityModal";
+import EditCertAuthorityModal from "./components/EditCertAuthorityModal";
const baseClass = "certificate-authorities";
@@ -30,7 +31,7 @@ const CertificateAuthorities = () => {
false
);
const [
- showDeleteCertAuthoirtyModal,
+ showDeleteCertAuthorityModal,
setShowDeleteCertAuthorityModal,
] = useState(false);
@@ -56,7 +57,6 @@ const CertificateAuthorities = () => {
};
const onEditCertAuthority = (cert: ICertAuthorityListData) => {
- // TODO: use useCallback
const certAuthority = getCertificateAuthority(
cert.id,
config?.integrations.ndes_scep_proxy,
@@ -69,7 +69,6 @@ const CertificateAuthorities = () => {
};
const onDeleteCertAuthority = (cert: ICertAuthorityListData) => {
- // TODO: use useCallback
const certAuthority = getCertificateAuthority(
cert.id,
config?.integrations.ndes_scep_proxy,
@@ -118,8 +117,13 @@ const CertificateAuthorities = () => {
onExit={() => setShowAddCertAuthorityModal(false)}
/>
)}
- {showEditCertAuthorityModal &&
Modal showing
}
- {showDeleteCertAuthoirtyModal &&
+ {showEditCertAuthorityModal && selectedCertAuthority && (
+ setShowEditCertAuthorityModal(false)}
+ />
+ )}
+ {showDeleteCertAuthorityModal &&
selectedCertAuthority &&
selectedListItemId && (
{
return (
<>
- {/* (
)}
- /> */}
+ />
(
diff --git a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DeleteCertificateAuthorityModal/helpers.ts b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DeleteCertificateAuthorityModal/helpers.ts
index 563e4d49aa..ec100e8067 100644
--- a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DeleteCertificateAuthorityModal/helpers.ts
+++ b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DeleteCertificateAuthorityModal/helpers.ts
@@ -7,7 +7,7 @@ import {
ICertificatesIntegrationDigicert,
IGlobalIntegrations,
} from "interfaces/integration";
-import { useContext } from "react";
+import { useCallback, useContext } from "react";
import { IDigicertFormData } from "../DigicertForm/DigicertForm";
export const useCertAuthorityDataGenerator = (
@@ -16,45 +16,48 @@ export const useCertAuthorityDataGenerator = (
) => {
const { config } = useContext(AppContext);
- const generateAddPatchData = (formData: IDigicertFormData) => {
- if (!config) return null;
+ const generateAddPatchData = useCallback(
+ (formData: IDigicertFormData) => {
+ if (!config) return null;
- const data: { integrations: Partial } = {
- integrations: {},
- };
+ const data: { integrations: Partial } = {
+ integrations: {},
+ };
- switch (certAuthorityType) {
- case "ndes":
- break;
- case "digicert":
- data.integrations.digicert = [
- ...(config.integrations.digicert || []),
- {
- name: formData.name,
- url: formData.url,
- api_token: formData.apiToken,
- profile_id: formData.profileId,
- certificate_common_name: formData.commonName,
- certificate_user_principal_names: [formData.userPrincipalName],
- certificate_seat_id: formData.certificateSeatId,
- },
- ];
- break;
- case "custom":
- break;
- default:
- break;
- }
+ switch (certAuthorityType) {
+ case "ndes":
+ break;
+ case "digicert":
+ data.integrations.digicert = [
+ ...(config.integrations.digicert || []),
+ {
+ name: formData.name,
+ url: formData.url,
+ api_token: formData.apiToken,
+ profile_id: formData.profileId,
+ certificate_common_name: formData.commonName,
+ certificate_user_principal_names: [formData.userPrincipalName],
+ certificate_seat_id: formData.certificateSeatId,
+ },
+ ];
+ break;
+ case "custom":
+ break;
+ default:
+ break;
+ }
- return data;
- };
+ return data;
+ },
+ [certAuthorityType, config]
+ );
/**
* generates the data to be sent to the API to delete the certificate authority.
* under the hood we are updating the app config object with the new data and
* have to generate the correct data for the PATCH request.
*/
- const generateDeletePatchData = () => {
+ const generateDeletePatchData = useCallback(() => {
if (!config) return null;
const data: { integrations: Partial } = {
@@ -90,16 +93,58 @@ export const useCertAuthorityDataGenerator = (
}
return data;
- };
+ }, [certAuthority, certAuthorityType, config]);
/**
* generates the data to be sent to the API to edit the certificate authority.
* under the hood we are updating the app config object with the new data and
* have to generate the correct data for the PATCH request.
*/
- const generateEditPatchData = (formData: IDigicertFormData) => {
- if (!config) return null;
- };
+ const generateEditPatchData = useCallback(
+ (formData: IDigicertFormData) => {
+ if (!config) return null;
+
+ const data: { integrations: Partial } = {
+ integrations: {},
+ };
+
+ switch (certAuthorityType) {
+ case "ndes":
+ break;
+ case "digicert":
+ data.integrations.digicert = config.integrations.digicert?.map(
+ (cert) => {
+ // only update the certificate authority that we are editing
+ if (
+ (certAuthority as ICertificatesIntegrationDigicert).name ===
+ cert.name
+ ) {
+ return {
+ name: formData.name,
+ url: formData.url,
+ api_token: formData.apiToken,
+ profile_id: formData.profileId,
+ certificate_common_name: formData.commonName,
+ certificate_user_principal_names: [
+ formData.userPrincipalName,
+ ],
+ certificate_seat_id: formData.certificateSeatId,
+ };
+ }
+ return cert;
+ }
+ );
+ break;
+ case "custom":
+ break;
+ default:
+ break;
+ }
+
+ return data;
+ },
+ [certAuthority, certAuthorityType, config]
+ );
return {
generateAddPatchData,
diff --git a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DigicertForm/DigicertForm.tsx b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DigicertForm/DigicertForm.tsx
index 53237eec62..9f30595060 100644
--- a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DigicertForm/DigicertForm.tsx
+++ b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DigicertForm/DigicertForm.tsx
@@ -5,7 +5,7 @@ import InputField from "components/forms/fields/InputField";
import Button from "components/buttons/Button";
import CustomLink from "components/CustomLink";
import TooltipWrapper from "components/TooltipWrapper";
-import { generateFormValidation, IDigicertFormValidation } from "./helpers";
+import { validateFormData, IDigicertFormValidation } from "./helpers";
const baseClass = "digicert-form";
@@ -59,7 +59,7 @@ const DigicertForm = ({
const onInputChange = (update: { name: string; value: string }) => {
setFormValidation(
- generateFormValidation({ ...formData, [update.name]: update.value })
+ validateFormData({ ...formData, [update.name]: update.value })
);
onChange(update);
};
diff --git a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DigicertForm/helpers.ts b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DigicertForm/helpers.ts
index 2d89ca38ba..ddc946f18b 100644
--- a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DigicertForm/helpers.ts
+++ b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/DigicertForm/helpers.ts
@@ -116,7 +116,7 @@ const getErrorMessage = (
};
// eslint-disable-next-line import/prefer-default-export
-export const generateFormValidation = (formData: IDigicertFormData) => {
+export const validateFormData = (formData: IDigicertFormData) => {
const formValidation: IDigicertFormValidation = {
isValid: true,
};
diff --git a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/EditCertAuthorityModal.tsx b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/EditCertAuthorityModal.tsx
new file mode 100644
index 0000000000..ecfe86cd05
--- /dev/null
+++ b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/EditCertAuthorityModal.tsx
@@ -0,0 +1,107 @@
+import React, { useContext, useRef, useState } from "react";
+
+import { NotificationContext } from "context/notification";
+import { AppContext } from "context/app";
+import {
+ ICertificateIntegration,
+ isDigicertCertIntegration,
+} from "interfaces/integration";
+import certificatesAPI from "services/entities/certificates";
+
+import Modal from "components/Modal";
+
+import DigicertForm from "../DigicertForm";
+import {
+ generateDefaultFormData,
+ generateErrorMessage,
+ getCertificateAuthorityType,
+} from "./helpers";
+import { ICertFormData } from "../AddCertAuthorityModal/AddCertAuthorityModal";
+import { useCertAuthorityDataGenerator } from "../DeleteCertificateAuthorityModal/helpers";
+
+const baseClass = "edit-cert-authority-modal";
+
+interface IEditCertAuthorityModalProps {
+ certAuthority: ICertificateIntegration;
+ onExit: () => void;
+}
+
+const EditCertAuthorityModal = ({
+ certAuthority,
+ onExit,
+}: IEditCertAuthorityModalProps) => {
+ const certType = useRef(getCertificateAuthorityType(certAuthority));
+ const { setConfig } = useContext(AppContext);
+ const { renderFlash } = useContext(NotificationContext);
+ const [isUpdating, setIsUpdating] = useState(false);
+ const [formData, setFormData] = useState(() =>
+ generateDefaultFormData(certAuthority)
+ );
+ const { generateEditPatchData } = useCertAuthorityDataGenerator(
+ certType.current,
+ certAuthority
+ );
+
+ const onChangeForm = (update: { name: string; value: string }) => {
+ setFormData((prevFormData) => {
+ if (!prevFormData) return prevFormData;
+
+ return {
+ ...prevFormData,
+ [update.name]: update.value,
+ };
+ });
+ };
+
+ const onEditCertAuthority = async () => {
+ const editPatchData = generateEditPatchData(formData);
+ setIsUpdating(true);
+ try {
+ const newConfig = await certificatesAPI.editCertAuthorityModal(
+ editPatchData
+ );
+ renderFlash("success", "Successfully edited your certificate authority.");
+ onExit();
+ setConfig(newConfig);
+ } catch (e) {
+ renderFlash("error", generateErrorMessage(e));
+ }
+ setIsUpdating(false);
+ };
+
+ const getFormComponent = () => {
+ if (isDigicertCertIntegration(certAuthority)) {
+ return DigicertForm;
+ }
+ return null;
+ };
+
+ const renderForm = () => {
+ const FormComponent = getFormComponent();
+ if (!FormComponent || !formData) return <>>;
+
+ return (
+
+ );
+ };
+
+ return (
+
+ {renderForm()}
+
+ );
+};
+
+export default EditCertAuthorityModal;
diff --git a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/_styles.scss b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/_styles.scss
new file mode 100644
index 0000000000..ff608def43
--- /dev/null
+++ b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/_styles.scss
@@ -0,0 +1,3 @@
+.edit-cert-authority-modal {
+
+}
diff --git a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/helpers.tsx b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/helpers.tsx
new file mode 100644
index 0000000000..d3f2e80f48
--- /dev/null
+++ b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/helpers.tsx
@@ -0,0 +1,40 @@
+import {
+ ICertificateAuthorityType,
+ ICertificateIntegration,
+ ICertificatesIntegrationDigicert,
+ isCustomSCEPCertIntegration,
+ isNDESCertIntegration,
+} from "interfaces/integration";
+
+import { ICertFormData } from "../AddCertAuthorityModal/AddCertAuthorityModal";
+
+const DEFAULT_ERROR_MESSAGE =
+ "Couldn't edit certificate authority. Please try again.";
+
+// eslint-disable-next-line import/prefer-default-export
+export const generateErrorMessage = (e: unknown) => {
+ return DEFAULT_ERROR_MESSAGE;
+};
+
+export const generateDefaultFormData = (
+ certAuthority: ICertificateIntegration
+): ICertFormData => {
+ const cert = certAuthority as ICertificatesIntegrationDigicert;
+ return {
+ name: cert.name,
+ url: cert.url,
+ apiToken: cert.api_token,
+ profileId: cert.profile_id,
+ commonName: cert.certificate_common_name,
+ userPrincipalName: cert.certificate_user_principal_names[0],
+ certificateSeatId: cert.certificate_seat_id,
+ };
+};
+
+export const getCertificateAuthorityType = (
+ certAuthority: ICertificateIntegration
+): ICertificateAuthorityType => {
+ if (isNDESCertIntegration(certAuthority)) return "ndes";
+ if (isCustomSCEPCertIntegration(certAuthority)) return "custom";
+ return "digicert";
+};
diff --git a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/index.ts b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/index.ts
new file mode 100644
index 0000000000..ecfc0036c3
--- /dev/null
+++ b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal/index.ts
@@ -0,0 +1 @@
+export { default } from "./EditCertAuthorityModal";
diff --git a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/helpers.tsx b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/helpers.tsx
index 65228043a1..17ff4c7512 100644
--- a/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/helpers.tsx
+++ b/frontend/pages/admin/IntegrationsPage/cards/CertificateAuthorities/helpers.tsx
@@ -2,6 +2,7 @@ import {
ICertificatesIntegrationCustomSCEP,
ICertificatesIntegrationDigicert,
ICertificatesIntegrationNDES,
+ isNDESCertIntegration,
} from "interfaces/integration";
export interface ICertAuthorityListData {
@@ -76,21 +77,24 @@ export const getCertificateAuthority = (
digicertCerts?: ICertificatesIntegrationDigicert[],
customProxies?: ICertificatesIntegrationCustomSCEP[]
) => {
- if (id === "ndes") {
- return ncspProxy as ICertificatesIntegrationNDES;
+ if (id === "ndes" && ncspProxy) {
+ return ncspProxy;
}
- if (id.includes("digicert")) {
- return digicertCerts?.find(
- (cert) => id.split("digicert-")[1] === cert.name
- ) as ICertificatesIntegrationDigicert;
+ if (id.includes("digicert") && digicertCerts) {
+ return (
+ digicertCerts.find((cert) => id.split("digicert-")[1] === cert.name) ??
+ null
+ );
}
- if (id.includes("custom-scep-proxy")) {
- return customProxies?.find(
- // TODO: remove custom scep id
- (cert) => id.split("custom-scep-proxy-")[1] === cert.id.toString()
- ) as ICertificatesIntegrationCustomSCEP;
+ if (id.includes("custom-scep-proxy") && customProxies) {
+ return (
+ customProxies?.find(
+ // TODO: remove custom scep id
+ (cert) => id.split("custom-scep-proxy-")[1] === cert.id.toString()
+ ) ?? null
+ );
}
return null;
diff --git a/frontend/services/entities/certificates.ts b/frontend/services/entities/certificates.ts
index 265376e3f9..928a0477a1 100644
--- a/frontend/services/entities/certificates.ts
+++ b/frontend/services/entities/certificates.ts
@@ -1,3 +1,4 @@
+import EditCertAuthorityModal from "pages/admin/IntegrationsPage/cards/CertificateAuthorities/components/EditCertAuthorityModal";
import configAPI from "./config";
export default {
@@ -5,6 +6,10 @@ export default {
return configAPI.update(updateData);
},
+ editCertAuthorityModal: (updateData: any): Promise => {
+ return configAPI.update(updateData);
+ },
+
deleteCertificateAuthority: (updateData: any): Promise => {
return configAPI.update(updateData);
},