mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 01:18:42 +00:00
fixes for various UI issues with cert authority feature (#27341)
For #26606 various fixes to the UI for the cert authority feature - [x] Manual QA for all new/changed functionality
This commit is contained in:
parent
49d4c1f7d2
commit
549c41e53d
11 changed files with 322 additions and 187 deletions
|
|
@ -1,5 +1,4 @@
|
|||
.add-cert-authority-modal {
|
||||
|
||||
&__cert-authority-dropdown {
|
||||
margin-bottom: $pad-large;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
import React from "react";
|
||||
|
||||
import CustomLink from "components/CustomLink";
|
||||
import { IDropdownOption } from "interfaces/dropdownOption";
|
||||
import { getErrorReason } from "interfaces/errors";
|
||||
|
||||
const DEFAULT_CERT_AUTHORITY_OPTIONS: IDropdownOption[] = [
|
||||
{ label: "Digicert", value: "digicert" },
|
||||
|
|
@ -24,10 +28,66 @@ export const generateDropdownOptions = (hasNDESCert: boolean) => {
|
|||
return DEFAULT_CERT_AUTHORITY_OPTIONS;
|
||||
};
|
||||
|
||||
const DEFAULT_ERROR_MESSAGE =
|
||||
"Couldn't add certificate authority. Please try again.";
|
||||
/**
|
||||
* errors used in the add certificate authority flow
|
||||
*/
|
||||
const DEFAULT_ERROR = "Please try again.";
|
||||
const INVALID_API_TOKEN_ERROR =
|
||||
"Invalid API token. Please correct and try again.";
|
||||
const INVALID_PROFILE_GUID_ERROR =
|
||||
"Invalid profile GUID. Please correct and try again.";
|
||||
const INVALID_URL_ERROR = "Invalid URL. Please correct and try again.";
|
||||
const PRIVATE_KEY_NOT_CONFIGURED_ERROR = (
|
||||
<>
|
||||
Private key must be configured.{" "}
|
||||
<CustomLink
|
||||
text="Learn more"
|
||||
url="https://learn-more-about/fleet-server-private-key"
|
||||
newTab
|
||||
variant="flash-message-link"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
const INVALID_SCEP_URL_ERROR =
|
||||
"Invalid SCEP URL. Please correct and try again.";
|
||||
const INVALID_ADMIN_URL_OR_CREDENTIALS_ERROR =
|
||||
"Invalid admin URL or credentials. Please correct and try again.";
|
||||
const NDES_PASSWORD_CACHE_FULL_ERROR =
|
||||
"The NDES password cache is full. Please increase the number of cached passwords in NDES and try again.";
|
||||
const INVALID_CHALLENGE_ERROR =
|
||||
"Invalid challenge. Please correct and try again.";
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const getErrorMessage = (e: unknown) => {
|
||||
return DEFAULT_ERROR_MESSAGE;
|
||||
/**
|
||||
* Gets the error message we want to display from the api error message.
|
||||
* This is used in both add and edit certificate authority flows.
|
||||
*/
|
||||
export const getDisplayErrMessage = (err: unknown) => {
|
||||
let message: string | JSX.Element = DEFAULT_ERROR;
|
||||
const reason = getErrorReason(err);
|
||||
|
||||
if (reason.includes("invalid API token")) {
|
||||
message = INVALID_API_TOKEN_ERROR;
|
||||
} else if (reason.includes("invalid profile GUID")) {
|
||||
message = INVALID_PROFILE_GUID_ERROR;
|
||||
} else if (reason.includes("invalid URL")) {
|
||||
message = INVALID_URL_ERROR;
|
||||
} else if (reason.includes("private key")) {
|
||||
message = PRIVATE_KEY_NOT_CONFIGURED_ERROR;
|
||||
} else if (reason.includes("invalid SCEP URL")) {
|
||||
message = INVALID_SCEP_URL_ERROR;
|
||||
} else if (reason.includes("invalid admin URL or credentials")) {
|
||||
message = INVALID_ADMIN_URL_OR_CREDENTIALS_ERROR;
|
||||
} else if (reason.includes("password cache is full")) {
|
||||
message = NDES_PASSWORD_CACHE_FULL_ERROR;
|
||||
} else if (reason.includes("invalid challenge")) {
|
||||
message = INVALID_CHALLENGE_ERROR;
|
||||
} else {
|
||||
message = DEFAULT_ERROR;
|
||||
}
|
||||
|
||||
return message;
|
||||
};
|
||||
|
||||
export const getErrorMessage = (err: unknown) => {
|
||||
return `Couldn't add certificate authority. ${getDisplayErrMessage(err)}`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
import React, { useState } from "react";
|
||||
import React, { useContext, useMemo, useState } from "react";
|
||||
|
||||
import { AppContext } from "context/app";
|
||||
|
||||
// @ts-ignore
|
||||
import InputField from "components/forms/fields/InputField";
|
||||
import Button from "components/buttons/Button";
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
|
||||
import { ICustomSCEPFormValidation, validateFormData } from "./helpers";
|
||||
import {
|
||||
generateFormValidations,
|
||||
ICustomSCEPFormValidation,
|
||||
validateFormData,
|
||||
} from "./helpers";
|
||||
|
||||
const baseClass = "ndes-form";
|
||||
|
||||
|
|
@ -19,6 +25,7 @@ interface ICustomSCEPFormProps {
|
|||
formData: ICustomSCEPFormData;
|
||||
submitBtnText: string;
|
||||
isSubmitting: boolean;
|
||||
isEditing?: boolean;
|
||||
onChange: (update: { name: string; value: string }) => void;
|
||||
onSubmit: () => void;
|
||||
onCancel: () => void;
|
||||
|
|
@ -28,10 +35,20 @@ const CustomSCEPForm = ({
|
|||
formData,
|
||||
submitBtnText,
|
||||
isSubmitting,
|
||||
isEditing = false,
|
||||
onChange,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}: ICustomSCEPFormProps) => {
|
||||
const { config } = useContext(AppContext);
|
||||
const validations = useMemo(
|
||||
() =>
|
||||
generateFormValidations(
|
||||
config?.integrations.custom_scep_proxy ?? [],
|
||||
isEditing
|
||||
),
|
||||
[config?.integrations.custom_scep_proxy]
|
||||
);
|
||||
const [
|
||||
formValidation,
|
||||
setFormValidation,
|
||||
|
|
@ -48,7 +65,10 @@ const CustomSCEPForm = ({
|
|||
|
||||
const onInputChange = (update: { name: string; value: string }) => {
|
||||
setFormValidation(
|
||||
validateFormData({ ...formData, [update.name]: update.value })
|
||||
validateFormData(
|
||||
{ ...formData, [update.name]: update.value },
|
||||
validations
|
||||
)
|
||||
);
|
||||
onChange(update);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { ICertificatesIntegrationCustomSCEP } from "interfaces/integration";
|
||||
|
||||
import valid_url from "components/forms/validators/valid_url";
|
||||
|
||||
import { ICustomSCEPFormData } from "./CustomSCEPForm";
|
||||
|
|
@ -21,56 +23,76 @@ interface IValidation {
|
|||
message?: IValidationMessage;
|
||||
}
|
||||
|
||||
const FORM_VALIDATIONS: Record<
|
||||
type IFormValidations = Record<
|
||||
IFormValidationKey,
|
||||
{ validations: IValidation[] }
|
||||
> = {
|
||||
name: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return formData.name.length > 0;
|
||||
>;
|
||||
|
||||
export const generateFormValidations = (
|
||||
customSCEPIntegrations: ICertificatesIntegrationCustomSCEP[],
|
||||
isEditing: boolean
|
||||
) => {
|
||||
const FORM_VALIDATIONS: IFormValidations = {
|
||||
name: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return formData.name.length > 0;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalidCharacters",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return /^[a-zA-Z0-9_]+$/.test(formData.name);
|
||||
{
|
||||
name: "invalidCharacters",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return /^[a-zA-Z0-9_]+$/.test(formData.name);
|
||||
},
|
||||
message:
|
||||
"Invalid characters. Only letters, numbers and underscores allowed.",
|
||||
},
|
||||
message:
|
||||
"Inalid characters. Only letters, numbers and underscores allowed.",
|
||||
},
|
||||
],
|
||||
},
|
||||
scepURL: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return formData.scepURL.length > 0;
|
||||
{
|
||||
name: "unique",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return (
|
||||
isEditing ||
|
||||
customSCEPIntegrations.find(
|
||||
(cert) => cert.name === formData.name
|
||||
) === undefined
|
||||
);
|
||||
},
|
||||
message: "Name is already used by another custom SCEP CA.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "validUrl",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return valid_url({ url: formData.scepURL });
|
||||
],
|
||||
},
|
||||
scepURL: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return formData.scepURL.length > 0;
|
||||
},
|
||||
},
|
||||
message: (formData: ICustomSCEPFormData) =>
|
||||
`${formData.scepURL} is not a valid URL`,
|
||||
},
|
||||
],
|
||||
},
|
||||
challenge: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return formData.challenge.length > 0;
|
||||
{
|
||||
name: "validUrl",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return valid_url({ url: formData.scepURL });
|
||||
},
|
||||
message: "Must be a valid URL.",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
challenge: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: ICustomSCEPFormData) => {
|
||||
return formData.challenge.length > 0;
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
return FORM_VALIDATIONS;
|
||||
};
|
||||
|
||||
const getErrorMessage = (
|
||||
|
|
@ -84,14 +106,17 @@ const getErrorMessage = (
|
|||
};
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const validateFormData = (formData: ICustomSCEPFormData) => {
|
||||
export const validateFormData = (
|
||||
formData: ICustomSCEPFormData,
|
||||
validationConfig: IFormValidations
|
||||
) => {
|
||||
const formValidation: ICustomSCEPFormValidation = {
|
||||
isValid: true,
|
||||
};
|
||||
|
||||
Object.keys(FORM_VALIDATIONS).forEach((key) => {
|
||||
const objKey = key as keyof typeof FORM_VALIDATIONS;
|
||||
const failedValidation = FORM_VALIDATIONS[objKey].validations.find(
|
||||
Object.keys(validationConfig).forEach((key) => {
|
||||
const objKey = key as keyof typeof validationConfig;
|
||||
const failedValidation = validationConfig[objKey].validations.find(
|
||||
(validation) => !validation.isValid(formData)
|
||||
);
|
||||
|
||||
|
|
@ -110,39 +135,3 @@ export const validateFormData = (formData: ICustomSCEPFormData) => {
|
|||
|
||||
return formValidation;
|
||||
};
|
||||
|
||||
const BAD_SCEP_URL_ERROR = "Invalid SCEP URL. Please correct and try again.";
|
||||
const BAD_CREDENTIALS_ERROR =
|
||||
"Couldn't add. Admin URL or credentials are invalid.";
|
||||
const CACHE_ERROR =
|
||||
"The NDES password cache is full. Please increase the number of cached passwords in NDES and try again. By default, NDES caches 5 passwords and they expire 60 minutes after they are created.";
|
||||
const INSUFFICIENT_PERMISSIONS_ERROR =
|
||||
"Couldn't add. This account doesn't have sufficient permissions. Please use the account with enroll permission.";
|
||||
const SCEP_URL_TIMEOUT_ERROR =
|
||||
"Couldn't add. Request to NDES (SCEP URL) timed out. Please try again.";
|
||||
const DEFAULT_ERROR =
|
||||
"Something went wrong updating your SCEP server. Please try again.";
|
||||
|
||||
// export const getErrorMessage = (
|
||||
// err: unknown,
|
||||
// formData: ICustomSCEPFormData
|
||||
// ) => {
|
||||
// const reason = getErrorReason(err);
|
||||
|
||||
// if (reason.includes("invalid admin URL or credentials")) {
|
||||
// return BAD_CREDENTIALS_ERROR;
|
||||
// } else if (reason.includes("the password cache is full")) {
|
||||
// return CACHE_ERROR;
|
||||
// } else if (reason.includes("does not have sufficient permissions")) {
|
||||
// INSUFFICIENT_PERMISSIONS_ERROR;
|
||||
// } else if (
|
||||
// reason.includes(formData.scepURL) &&
|
||||
// reason.includes("context deadline exceeded")
|
||||
// ) {
|
||||
// return SCEP_URL_TIMEOUT_ERROR;
|
||||
// } else if (reason.includes("invalid SCEP URL")) {
|
||||
// return BAD_SCEP_URL_ERROR;
|
||||
// }
|
||||
|
||||
// return DEFAULT_ERROR;
|
||||
// };
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
import React, { useState } from "react";
|
||||
import React, { useContext, useMemo, useState } from "react";
|
||||
|
||||
import { AppContext } from "context/app";
|
||||
|
||||
// @ts-ignore
|
||||
import InputField from "components/forms/fields/InputField";
|
||||
import Button from "components/buttons/Button";
|
||||
import CustomLink from "components/CustomLink";
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
import { validateFormData, IDigicertFormValidation } from "./helpers";
|
||||
import {
|
||||
validateFormData,
|
||||
IDigicertFormValidation,
|
||||
generateFormValidations,
|
||||
} from "./helpers";
|
||||
|
||||
const baseClass = "digicert-form";
|
||||
|
||||
|
|
@ -23,6 +29,7 @@ interface IDigicertFormProps {
|
|||
formData: IDigicertFormData;
|
||||
submitBtnText: string;
|
||||
isSubmitting: boolean;
|
||||
isEditing?: boolean;
|
||||
onChange: (update: { name: string; value: string }) => void;
|
||||
onSubmit: () => void;
|
||||
onCancel: () => void;
|
||||
|
|
@ -32,10 +39,18 @@ const DigicertForm = ({
|
|||
formData,
|
||||
submitBtnText,
|
||||
isSubmitting,
|
||||
isEditing = false,
|
||||
onChange,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}: IDigicertFormProps) => {
|
||||
const { config } = useContext(AppContext);
|
||||
const validations = useMemo(
|
||||
() =>
|
||||
generateFormValidations(config?.integrations.digicert ?? [], isEditing),
|
||||
[config?.integrations.digicert, isEditing]
|
||||
);
|
||||
|
||||
const [formValidation, setFormValidation] = useState<IDigicertFormValidation>(
|
||||
{
|
||||
isValid: false,
|
||||
|
|
@ -59,7 +74,10 @@ const DigicertForm = ({
|
|||
|
||||
const onInputChange = (update: { name: string; value: string }) => {
|
||||
setFormValidation(
|
||||
validateFormData({ ...formData, [update.name]: update.value })
|
||||
validateFormData(
|
||||
{ ...formData, [update.name]: update.value },
|
||||
validations
|
||||
)
|
||||
);
|
||||
onChange(update);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
import { ICertificatesIntegrationDigicert } from "interfaces/integration";
|
||||
|
||||
import valid_url from "components/forms/validators/valid_url";
|
||||
|
||||
import { IDigicertFormData } from "./DigicertForm";
|
||||
|
||||
// TODO: create a validator abstraction for this and the other form validation files
|
||||
|
|
@ -23,86 +26,105 @@ interface IValidation {
|
|||
message?: IValidationMessage;
|
||||
}
|
||||
|
||||
const FORM_VALIDATIONS: Record<
|
||||
type IFormValidations = Record<
|
||||
IFormValidationKey,
|
||||
{ validations: IValidation[] }
|
||||
> = {
|
||||
name: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.name.length > 0;
|
||||
>;
|
||||
|
||||
export const generateFormValidations = (
|
||||
digicertIntegrations: ICertificatesIntegrationDigicert[],
|
||||
isEditing: boolean
|
||||
) => {
|
||||
const FORM_VALIDATIONS: IFormValidations = {
|
||||
name: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.name.length > 0;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalidCharacters",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return /^[a-zA-Z0-9_]+$/.test(formData.name);
|
||||
{
|
||||
name: "invalidCharacters",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return /^[a-zA-Z0-9_]+$/.test(formData.name);
|
||||
},
|
||||
message:
|
||||
"Invalid characters. Only letters, numbers and underscores allowed.",
|
||||
},
|
||||
message:
|
||||
"Inalid characters. Only letters, numbers and underscores allowed.",
|
||||
},
|
||||
],
|
||||
},
|
||||
url: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.url.length > 0;
|
||||
{
|
||||
name: "unique",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return (
|
||||
isEditing ||
|
||||
digicertIntegrations.find(
|
||||
(cert) => cert.name === formData.name
|
||||
) === undefined
|
||||
);
|
||||
},
|
||||
message: "Name is already used by another DigiCert CA.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "validUrl",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return valid_url({ url: formData.url });
|
||||
],
|
||||
},
|
||||
url: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.url.length > 0;
|
||||
},
|
||||
},
|
||||
message: (formData: IDigicertFormData) =>
|
||||
`${formData.url} is not a valid URL`,
|
||||
},
|
||||
],
|
||||
},
|
||||
apiToken: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.apiToken.length > 0;
|
||||
{
|
||||
name: "validUrl",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return valid_url({ url: formData.url });
|
||||
},
|
||||
message: "Must be a valid URL.",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
profileId: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.profileId.length > 0;
|
||||
],
|
||||
},
|
||||
apiToken: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.apiToken.length > 0;
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
commonName: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.commonName.length > 0;
|
||||
],
|
||||
},
|
||||
profileId: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.profileId.length > 0;
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
certificateSeatId: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.certificateSeatId.length > 0;
|
||||
],
|
||||
},
|
||||
commonName: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.commonName.length > 0;
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
certificateSeatId: {
|
||||
validations: [
|
||||
{
|
||||
name: "required",
|
||||
isValid: (formData: IDigicertFormData) => {
|
||||
return formData.certificateSeatId.length > 0;
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
return FORM_VALIDATIONS;
|
||||
};
|
||||
|
||||
const getErrorMessage = (
|
||||
|
|
@ -115,15 +137,17 @@ const getErrorMessage = (
|
|||
return message(formData);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const validateFormData = (formData: IDigicertFormData) => {
|
||||
export const validateFormData = (
|
||||
formData: IDigicertFormData,
|
||||
validationConfig: IFormValidations
|
||||
) => {
|
||||
const formValidation: IDigicertFormValidation = {
|
||||
isValid: true,
|
||||
};
|
||||
|
||||
Object.keys(FORM_VALIDATIONS).forEach((key) => {
|
||||
const objKey = key as keyof typeof FORM_VALIDATIONS;
|
||||
const failedValidation = FORM_VALIDATIONS[objKey].validations.find(
|
||||
Object.keys(validationConfig).forEach((key) => {
|
||||
const objKey = key as keyof typeof validationConfig;
|
||||
const failedValidation = validationConfig[objKey].validations.find(
|
||||
(validation) => !validation.isValid(formData)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import Modal from "components/Modal";
|
|||
|
||||
import {
|
||||
generateDefaultFormData,
|
||||
generateErrorMessage,
|
||||
getErrorMessage,
|
||||
getCertificateAuthorityType,
|
||||
} from "./helpers";
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ const EditCertAuthorityModal = ({
|
|||
onExit();
|
||||
setConfig(newConfig);
|
||||
} catch (e) {
|
||||
renderFlash("error", generateErrorMessage(e));
|
||||
renderFlash("error", getErrorMessage(e));
|
||||
}
|
||||
setIsUpdating(false);
|
||||
};
|
||||
|
|
@ -93,6 +93,7 @@ const EditCertAuthorityModal = ({
|
|||
formData={formData}
|
||||
submitBtnText="Save"
|
||||
isSubmitting={isUpdating}
|
||||
isEditing
|
||||
onChange={onChangeForm}
|
||||
onSubmit={onEditCertAuthority}
|
||||
onCancel={onExit}
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
.edit-cert-authority-modal {
|
||||
|
||||
}
|
||||
|
|
@ -2,22 +2,13 @@ import {
|
|||
ICertificateAuthorityType,
|
||||
ICertificateIntegration,
|
||||
ICertificatesIntegrationCustomSCEP,
|
||||
ICertificatesIntegrationDigicert,
|
||||
ICertificatesIntegrationNDES,
|
||||
isCustomSCEPCertIntegration,
|
||||
isDigicertCertIntegration,
|
||||
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;
|
||||
};
|
||||
import { getDisplayErrMessage } from "../AddCertAuthorityModal/helpers";
|
||||
|
||||
export const getCertificateAuthorityType = (
|
||||
certAuthority: ICertificateIntegration
|
||||
|
|
@ -56,3 +47,7 @@ export const generateDefaultFormData = (
|
|||
challenge: customSCEPcert.challenge,
|
||||
};
|
||||
};
|
||||
|
||||
export const getErrorMessage = (err: unknown) => {
|
||||
return `Couldn't edit certificate authority. ${getDisplayErrMessage(err)}`;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ interface INDESFormProps {
|
|||
formData: INDESFormData;
|
||||
submitBtnText: string;
|
||||
isSubmitting: boolean;
|
||||
isEditing?: boolean;
|
||||
onChange: (update: { name: string; value: string }) => void;
|
||||
onSubmit: () => void;
|
||||
onCancel: () => void;
|
||||
|
|
@ -29,6 +30,7 @@ const NDESForm = ({
|
|||
formData,
|
||||
submitBtnText,
|
||||
isSubmitting,
|
||||
isEditing = false,
|
||||
onChange,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
|
|
@ -58,6 +60,7 @@ const NDESForm = ({
|
|||
label="SCEP URL"
|
||||
name="scepURL"
|
||||
value={scepURL}
|
||||
error={formValidation.scepURL?.message}
|
||||
onChange={onInputChange}
|
||||
parseTarget
|
||||
placeholder="https://example.com/certsrv/mscep/mscep.dll"
|
||||
|
|
@ -67,6 +70,7 @@ const NDESForm = ({
|
|||
label="Admin URL"
|
||||
name="adminURL"
|
||||
value={adminURL}
|
||||
error={formValidation.adminURL?.message}
|
||||
onChange={onInputChange}
|
||||
parseTarget
|
||||
placeholder="https://example.com/certsrv/mscep_admin/"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
import { getErrorReason } from "interfaces/errors";
|
||||
|
||||
import valid_url from "components/forms/validators/valid_url";
|
||||
|
||||
import { INDESFormData } from "./NDESForm";
|
||||
|
||||
// TODO: create a validator abstraction for this and the other form validation files
|
||||
|
||||
export interface INDESFormValidation {
|
||||
isValid: boolean;
|
||||
scepURL?: { isValid: boolean };
|
||||
adminURL?: { isValid: boolean };
|
||||
scepURL?: { isValid: boolean; message?: string };
|
||||
adminURL?: { isValid: boolean; message?: string };
|
||||
username?: { isValid: boolean };
|
||||
password?: { isValid: boolean };
|
||||
}
|
||||
|
|
@ -33,6 +36,13 @@ const FORM_VALIDATIONS: Record<
|
|||
return formData.scepURL.length > 0;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "validUrl",
|
||||
isValid: (formData: INDESFormData) => {
|
||||
return valid_url({ url: formData.scepURL });
|
||||
},
|
||||
message: "Must be a valid URL.",
|
||||
},
|
||||
],
|
||||
},
|
||||
adminURL: {
|
||||
|
|
@ -43,6 +53,13 @@ const FORM_VALIDATIONS: Record<
|
|||
return formData.adminURL.length > 0;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "validUrl",
|
||||
isValid: (formData: INDESFormData) => {
|
||||
return valid_url({ url: formData.adminURL });
|
||||
},
|
||||
message: "Must be a valid URL",
|
||||
},
|
||||
],
|
||||
},
|
||||
username: {
|
||||
|
|
@ -67,6 +84,16 @@ const FORM_VALIDATIONS: Record<
|
|||
},
|
||||
};
|
||||
|
||||
const getValifationErrorMessage = (
|
||||
formData: INDESFormData,
|
||||
message?: IValidationMessage
|
||||
) => {
|
||||
if (message === undefined || typeof message === "string") {
|
||||
return message;
|
||||
}
|
||||
return message(formData);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const validateFormData = (formData: INDESFormData) => {
|
||||
const formValidation: INDESFormValidation = {
|
||||
|
|
@ -87,6 +114,7 @@ export const validateFormData = (formData: INDESFormData) => {
|
|||
formValidation.isValid = false;
|
||||
formValidation[objKey] = {
|
||||
isValid: false,
|
||||
message: getValifationErrorMessage(formData, failedValidation.message),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue