Skip to content

Commit

Permalink
Fix integration issues
Browse files Browse the repository at this point in the history
  • Loading branch information
gillespi314 committed Nov 23, 2024
1 parent ef18576 commit 0248898
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 115 deletions.
3 changes: 3 additions & 0 deletions frontend/interfaces/integration.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { IPkiConfig } from "./pki";

export type IIntegrationType = "jira" | "zendesk";
export interface IJiraIntegration {
url: string;
Expand Down Expand Up @@ -92,6 +94,7 @@ export interface IZendeskJiraIntegrations {
export interface IGlobalIntegrations extends IZendeskJiraIntegrations {
google_calendar?: IGlobalCalendarIntegration[] | null;
ndes_scep_proxy?: IScepIntegration | null;
digicert_pki?: IPkiConfig[] | null;
}

export interface ITeamIntegrations extends IZendeskJiraIntegrations {
Expand Down
19 changes: 14 additions & 5 deletions frontend/interfaces/pki.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
export type IPkiTemplate = {
profile_id: number;
export interface IPkiCert {
name: string;
sha256: string;
not_valid_after: string;
}

export interface IPkiTemplate {
profile_id: string;
name: string;
common_name: string;
san: string;
san: { user_principal_names: string[] };
seat_id: string;
};
}

export type IPkiConfig = { name: string; templates: IPkiTemplate[] };
export interface IPkiConfig {
pki_name: string;
templates: IPkiTemplate[];
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import React, { useCallback, useContext, useRef, useState } from "react";
import { noop } from "lodash";
import React, {
useCallback,
useContext,
useMemo,
useRef,
useState,
} from "react";

import { useQuery } from "react-query";
import { InjectedRouter } from "react-router";
Expand All @@ -10,7 +15,11 @@ import PATHS from "router/paths";

import { AppContext } from "context/app";

import { IPkiConfig } from "interfaces/pki";
import { IConfig } from "interfaces/config";
import { IPkiCert, IPkiConfig } from "interfaces/pki";

import configApi from "services/entities/config";
import pkiApi, { IPkiListCertsResponse } from "services/entities/pki";

import BackLink from "components/BackLink";
import Button from "components/buttons/Button";
Expand Down Expand Up @@ -53,42 +62,56 @@ const PkiPage = ({ router }: { router: InjectedRouter }) => {
const selectedPki = useRef<IPkiConfig | null>(null);

const {
data: pkiConfigs,
error: errorPkiConfigs,
data: pkiCerts,
error: errorCerts,
isLoading,
isRefetching,
refetch,
} = useQuery<IPkiConfig[], AxiosError>(
["pkiConfigs"],
() =>
Promise.resolve([
{
name: "test_config",
templates: [
{
profile_id: 1,
name: "test",
common_name: "test",
san: "test",
seat_id: "test",
},
],
},
]),
refetch: refetchCerts,
} = useQuery<IPkiListCertsResponse, AxiosError, IPkiCert[]>(
["pki_certs"],
() => pkiApi.listCerts(),
{
refetchOnWindowFocus: false,
retry: (tries, error) =>
error.status !== 404 && error.status !== 400 && tries <= 3,
select: (data) => data.certificates,
enabled: isPremiumTier,
}
);

const {
data: pkiConfigs,
error: errorConfigs,
isLoading: isLoadingConfigs,
isRefetching: isRefetchingConfigs,
refetch: refetchConfigs,
} = useQuery<IConfig, AxiosError, IPkiConfig[]>(
["digicert_pki"],
() => configApi.loadAll(),
{
refetchOnWindowFocus: false,
select: (data) => data.integrations.digicert_pki || [], // TODO: handle no value
enabled: isPremiumTier,
}
);

const tableData = useMemo(() => {
const dict: Record<string, IPkiConfig> = {};
pkiConfigs?.forEach((pki) => {
dict[pki.pki_name] = pki;
});
pkiCerts?.forEach((pki) => {
if (!dict[pki.name]) {
dict[pki.name] = { pki_name: pki.name, templates: [] };
}
});
return Object.values(dict);
}, [pkiConfigs, pkiCerts]);

const onAdd = () => {
setShowAddPkiModal(true);
};

const onAdded = () => {
refetch();
refetchCerts();
setShowAddPkiModal(false);
};

Expand All @@ -104,9 +127,9 @@ const PkiPage = ({ router }: { router: InjectedRouter }) => {

const onEditedTemplate = useCallback(() => {
selectedPki.current = null;
refetch();
refetchConfigs();
setShowEditTemplateModal(false);
}, [refetch]);
}, [refetchConfigs]);

const onDelete = (pkiConfig: IPkiConfig) => {
selectedPki.current = pkiConfig;
Expand All @@ -120,15 +143,16 @@ const PkiPage = ({ router }: { router: InjectedRouter }) => {

const onDeleted = useCallback(() => {
selectedPki.current = null;
refetch();
refetchCerts();
refetchConfigs();
setShowDeleteModal(false);
}, [refetch]);
}, [refetchCerts, refetchConfigs]);

if (isLoading || isRefetching) {
return <Spinner />;
}
// if (isLoading || isRefetching || isLoadingConfigs || isRefetchingConfigs) {
// return <Spinner />;
// }

const showDataError = errorPkiConfigs && errorPkiConfigs.status !== 404;
const showDataError = errorCerts || errorConfigs;

const renderContent = () => {
if (!isPremiumTier) {
Expand All @@ -146,7 +170,7 @@ const PkiPage = ({ router }: { router: InjectedRouter }) => {
);
}

if (isLoading) {
if (isLoading || isRefetching || isLoadingConfigs || isRefetchingConfigs) {
return <Spinner />;
}

Expand All @@ -159,15 +183,15 @@ const PkiPage = ({ router }: { router: InjectedRouter }) => {
);
}

if (!pkiConfigs?.length) {
if (!pkiCerts?.length) {
return <AddPkiMessage onAddPki={onAdd} />;
}

return (
<>
<p>To help your end users connect to Wi-Fi, you can add your PKI.</p>
<PkiTable
data={pkiConfigs}
data={tableData}
onEdit={onEditTemplate}
onDelete={onDelete}
/>
Expand All @@ -187,7 +211,7 @@ const PkiPage = ({ router }: { router: InjectedRouter }) => {
<div className={`${baseClass}__page-header-section`}>
<h1>Public key infrastructure (PKI)</h1>
{isPremiumTier &&
pkiConfigs?.length !== 0 &&
!!pkiCerts?.length &&
!!config?.mdm.enabled_and_configured && (
<Button variant="brand" onClick={onAdd}>
Add PKI
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface IDeletePkiModalProps {
}

const DeletePkiModal = ({
pkiConfig: { name },
pkiConfig: { pki_name: name },
onCancel,
onDeleted,
}: IDeletePkiModalProps) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import React, { useCallback, useState } from "react";

import { NotificationContext } from "context/notification";

import { IFormField } from "interfaces/form_field";
import { IPkiConfig, IPkiTemplate } from "interfaces/pki";

import pkiApi from "services/entities/pki";

import Button from "components/buttons/Button";
// @ts-ignore
import InputField from "components/forms/fields/InputField";
import Modal from "components/Modal";
import TooltipWrapper from "components/TooltipWrapper";

import { IPkiConfig, IPkiTemplate } from "interfaces/pki";

const baseClass = "pki-edit-template-modal";

type IFormErrors = Partial<Record<keyof IPkiTemplate, string>>;
Expand Down Expand Up @@ -39,6 +42,37 @@ const TEMPLATE_HELP_TEXT: Record<
"Certificates delivered to your hosts using will be assgined to this seat ID in DigiCert.",
};

// TODO: we should revisit this in design after the PoC
const flattenTemplate = (template: IPkiTemplate | undefined) => {
if (!template) {
return {
profile_id: "",
name: "",
common_name: "",
san: "",
seat_id: "",
};
}
return {
profile_id: template.profile_id.toString(),
name: template.name,
common_name: template.common_name,
san: template.san.user_principal_names[0],
seat_id: template.seat_id,
};
};

// TODO: we should revisit this in design after the PoC
const unflattenTemplate = (formData: Record<keyof IPkiTemplate, string>) => {
return {
profile_id: formData.profile_id,
name: formData.name,
common_name: formData.common_name,
san: { user_principal_names: [formData.san] },
seat_id: formData.seat_id,
};
};

const EditTemplateModal = ({
pkiConfig,
onCancel,
Expand All @@ -48,14 +82,10 @@ const EditTemplateModal = ({
onCancel: () => void;
onSuccess: () => void;
}) => {
const [formData, setFormData] = useState<IPkiTemplate>(
pkiConfig.templates[0] || {
profile_id: "",
name: "",
common_name: "",
san: "",
seat_id: "",
}
const { renderFlash } = React.useContext(NotificationContext);

const [formData, setFormData] = useState<Record<keyof IPkiTemplate, string>>(
flattenTemplate(pkiConfig.templates[0])
);
const [formErrors, setFormErrors] = useState<IFormErrors>({});

Expand All @@ -65,40 +95,20 @@ const EditTemplateModal = ({
};

const onSubmit = useCallback(async () => {
// validate
const errors: IFormErrors = {};

if (!formData.profile_id) {
errors.profile_id = "Profile ID is required";
}
// TODO: validations

if (!formData.name) {
errors.name = "Name is required";
}

if (!formData.common_name) {
errors.common_name = "Common name is required";
}

if (!formData.san) {
errors.san = "Subject alternative name is required";
}

if (!formData.seat_id) {
errors.seat_id = "Seat ID is required";
}
// TODO: how do we handle multiple array elements at top-level (i.e. certs by pki_name) and at cert-level
// (templates by template name)?

if (Object.keys(errors).length) {
setFormErrors(errors);
return;
try {
await pkiApi.addTemplate(pkiConfig.pki_name, unflattenTemplate(formData));
onSuccess();
} catch {
renderFlash("error", "Could not save template");
}
}, [formData, onSuccess, pkiConfig.pki_name, renderFlash]);

// save
console.log("Save", formData);
onSuccess();
}, [formData, onSuccess]);

const disableInput = !pkiConfig.templates.length;
const disableInput = !!pkiConfig.templates.length;
const disableSave = Object.values(formData).some((v) => !v);

const isSaving = false;
Expand Down Expand Up @@ -137,7 +147,7 @@ const EditTemplateModal = ({
<InputField
inputWrapperClass={`${baseClass}__admin-url-input`}
label="Certificate common name (CN)"
name="coomon_name"
name="common_name"
value={formData.common_name}
onChange={onInputChange}
parseTarget
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,19 @@ const baseClass = "pki-table";

interface IPkiTableProps {
data: IPkiConfig[];
// onEditTokenTeam: (token: IPkiConfig) => void;
onEdit: (pkiConfig: IPkiConfig) => void;
onDelete: (pkiConfig: IPkiConfig) => void;
}

const PkiTable = ({
data,
// onEditTokenTeam,
onEdit,
onDelete,
}: IPkiTableProps) => {
const PkiTable = ({ data, onEdit, onDelete }: IPkiTableProps) => {
const onSelectAction = (action: string, pkiConfig: IPkiConfig) => {
switch (action) {
case "view_template":
onEdit(pkiConfig);
break;
// case "add_template":
// onRenewToken(pkiConfig);
// break;
case "add_template":
onEdit(pkiConfig);
break;
case "delete":
onDelete(pkiConfig);
break;
Expand Down
Loading

0 comments on commit 0248898

Please sign in to comment.