import React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Controller, useForm } from 'react-hook-form';
import i18next from 'i18next';
import {
validateServerName,
validateIsSafePort,
validatePort,
validatePortQuic,
validatePortTLS,
validatePlainDns,
} from '../../../helpers/validators';
import KeyStatus from './KeyStatus';
import CertificateStatus from './CertificateStatus';
import {
DNS_OVER_QUIC_PORT,
DNS_OVER_TLS_PORT,
STANDARD_HTTPS_PORT,
ENCRYPTION_SOURCE,
} from '../../../helpers/constants';
import { Checkbox } from '../../ui/Controls/Checkbox';
import { Radio } from '../../ui/Controls/Radio';
import { Input } from '../../ui/Controls/Input';
import { Textarea } from '../../ui/Controls/Textarea';
import { EncryptionData } from '../../../initialState';
import { toNumber } from '../../../helpers/form';
const certificateSourceOptions = [
{
label: i18next.t('encryption_certificates_source_path'),
value: ENCRYPTION_SOURCE.PATH,
},
{
label: i18next.t('encryption_certificates_source_content'),
value: ENCRYPTION_SOURCE.CONTENT,
},
];
const keySourceOptions = [
{
label: i18next.t('encryption_key_source_path'),
value: ENCRYPTION_SOURCE.PATH,
},
{
label: i18next.t('encryption_key_source_content'),
value: ENCRYPTION_SOURCE.CONTENT,
},
];
const validationMessage = (warningValidation: string, isWarning: boolean) => {
if (!warningValidation) {
return null;
}
if (isWarning) {
return (
encryption_warning: {warningValidation}
);
}
return (
);
};
export type EncryptionFormValues = {
enabled?: boolean;
serve_plain_dns?: boolean;
server_name?: string;
force_https?: boolean;
port_https?: number;
port_dns_over_tls?: number;
port_dns_over_quic?: number;
certificate_chain?: string;
private_key?: string;
certificate_path?: string;
private_key_path?: string;
certificate_source?: string;
key_source?: string;
private_key_saved?: boolean;
};
type Props = {
initialValues: EncryptionFormValues;
encryption: EncryptionData;
onSubmit: (values: EncryptionFormValues) => void;
debouncedConfigValidation: (values: EncryptionFormValues) => void;
setTlsConfig: (values: Partial) => void;
validateTlsConfig: (values: Partial) => void;
};
const defaultValues = {
enabled: false,
serve_plain_dns: true,
server_name: '',
force_https: false,
port_https: STANDARD_HTTPS_PORT,
port_dns_over_tls: DNS_OVER_TLS_PORT,
port_dns_over_quic: DNS_OVER_QUIC_PORT,
certificate_chain: '',
private_key: '',
certificate_path: '',
private_key_path: '',
certificate_source: ENCRYPTION_SOURCE.PATH,
key_source: ENCRYPTION_SOURCE.PATH,
private_key_saved: false,
};
export const Form = ({
initialValues,
encryption,
onSubmit,
setTlsConfig,
debouncedConfigValidation,
validateTlsConfig,
}: Props) => {
const { t } = useTranslation();
const {
not_after,
valid_chain,
valid_key,
valid_cert,
valid_pair,
dns_names,
key_type,
issuer,
subject,
warning_validation,
processingConfig,
processingValidate,
} = encryption;
const {
control,
handleSubmit,
watch,
reset,
setValue,
setError,
getValues,
formState: { isSubmitting, isValid },
} = useForm({
defaultValues: {
...defaultValues,
...initialValues,
},
mode: 'onBlur',
});
const {
enabled: isEnabled,
serve_plain_dns: servePlainDns,
certificate_chain: certificateChain,
private_key: privateKey,
private_key_path: privateKeyPath,
key_source: privateKeySource,
private_key_saved: privateKeySaved,
certificate_path: certificatePath,
certificate_source: certificateSource,
} = watch();
const handleBlur = () => {
debouncedConfigValidation(getValues());
};
const isSavingDisabled = () => {
const processing = isSubmitting || processingConfig || processingValidate;
if (servePlainDns && !isEnabled) {
return !isValid || processing;
}
return !isValid || processing || !valid_key || !valid_cert || !valid_pair;
};
const clearFields = () => {
if (window.confirm(t('encryption_reset'))) {
reset();
setTlsConfig(defaultValues);
validateTlsConfig(defaultValues);
}
};
const validatePorts = (values: EncryptionFormValues) => {
const errors: { port_dns_over_tls?: string; port_https?: string } = {};
if (values.port_dns_over_tls && values.port_https) {
if (values.port_dns_over_tls === values.port_https) {
errors.port_dns_over_tls = i18next.t('form_error_equal');
errors.port_https = i18next.t('form_error_equal');
}
}
return errors;
};
const onFormSubmit = (data: EncryptionFormValues) => {
const validationErrors = validatePorts(data);
if (Object.keys(validationErrors).length > 0) {
Object.entries(validationErrors).forEach(([field, message]) => {
setError(field as keyof EncryptionFormValues, { type: 'manual', message });
});
} else {
onSubmit(data);
}
};
const isDisabled = isSavingDisabled();
const isWarning = valid_key && valid_cert && valid_pair;
return (
);
};