all: sync with master

This commit is contained in:
Ainar Garipov
2024-07-03 15:38:37 +03:00
parent f73717ec08
commit 158d4f0249
352 changed files with 33842 additions and 33276 deletions

View File

@@ -1,31 +1,27 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { withTranslation, Trans } from 'react-i18next';
import format from 'date-fns/format';
import { EMPTY_DATE } from '../../../helpers/constants';
const CertificateStatus = ({
validChain,
validCert,
subject,
issuer,
notAfter,
dnsNames,
}) => (
interface CertificateStatusProps {
validChain: boolean;
validCert: boolean;
subject?: string;
issuer?: string;
notAfter?: string;
dnsNames?: string[];
}
const CertificateStatus = ({ validChain, validCert, subject, issuer, notAfter, dnsNames }: CertificateStatusProps) => (
<Fragment>
<div className="form__label form__label--bold">
<Trans>encryption_status</Trans>:
</div>
<ul className="encryption__list">
<li
className={validChain ? 'text-success' : 'text-danger'}
>
{validChain ? (
<Trans>encryption_chain_valid</Trans>
) : (
<Trans>encryption_chain_invalid</Trans>
)}
<li className={validChain ? 'text-success' : 'text-danger'}>
{validChain ? <Trans>encryption_chain_valid</Trans> : <Trans>encryption_chain_invalid</Trans>}
</li>
{validCert && (
<Fragment>
@@ -59,13 +55,4 @@ const CertificateStatus = ({
</Fragment>
);
CertificateStatus.propTypes = {
validChain: PropTypes.bool.isRequired,
validCert: PropTypes.bool.isRequired,
subject: PropTypes.string,
issuer: PropTypes.string,
notAfter: PropTypes.string,
dnsNames: PropTypes.arrayOf(PropTypes.string),
};
export default withTranslation()(CertificateStatus);

View File

@@ -1,32 +1,39 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { Field, reduxForm, formValueSelector } from 'redux-form';
import { Trans, withTranslation } from 'react-i18next';
import flow from 'lodash/flow';
import { renderInputField, CheckboxField, renderRadioField, toNumber } from '../../../helpers/form';
import {
renderInputField,
CheckboxField,
renderRadioField,
toNumber,
} from '../../../helpers/form';
import {
validateServerName, validateIsSafePort, validatePort, validatePortQuic, validatePortTLS, validatePlainDns,
validateServerName,
validateIsSafePort,
validatePort,
validatePortQuic,
validatePortTLS,
validatePlainDns,
} from '../../../helpers/validators';
import i18n from '../../../i18n';
import KeyStatus from './KeyStatus';
import CertificateStatus from './CertificateStatus';
import {
DNS_OVER_QUIC_PORT, DNS_OVER_TLS_PORT, FORM_NAME, STANDARD_HTTPS_PORT, ENCRYPTION_SOURCE,
DNS_OVER_QUIC_PORT,
DNS_OVER_TLS_PORT,
FORM_NAME,
STANDARD_HTTPS_PORT,
ENCRYPTION_SOURCE,
} from '../../../helpers/constants';
const validate = (values) => {
const errors = {};
const validate = (values: any) => {
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 = i18n.t('form_error_equal');
errors.port_https = i18n.t('form_error_equal');
}
}
@@ -34,7 +41,7 @@ const validate = (values) => {
return errors;
};
const clearFields = (change, setTlsConfig, validateTlsConfig, t) => {
const clearFields = (change: any, setTlsConfig: any, validateTlsConfig: any, t: any) => {
const fields = {
private_key: '',
certificate_chain: '',
@@ -52,13 +59,14 @@ const clearFields = (change, setTlsConfig, validateTlsConfig, t) => {
// eslint-disable-next-line no-alert
if (window.confirm(t('encryption_reset'))) {
Object.keys(fields)
.forEach((field) => change(field, fields[field]));
setTlsConfig(fields);
validateTlsConfig(fields);
}
};
const validationMessage = (warningValidation, isWarning) => {
const validationMessage = (warningValidation: any, isWarning: any) => {
if (!warningValidation) {
return null;
}
@@ -66,7 +74,9 @@ const validationMessage = (warningValidation, isWarning) => {
if (isWarning) {
return (
<div className="col-12">
<p><Trans>encryption_warning</Trans>: {warningValidation}</p>
<p>
<Trans>encryption_warning</Trans>: {warningValidation}
</p>
</div>
);
}
@@ -78,7 +88,41 @@ const validationMessage = (warningValidation, isWarning) => {
);
};
let Form = (props) => {
interface FormProps {
handleSubmit: (...args: unknown[]) => string;
handleChange?: (...args: unknown[]) => unknown;
isEnabled: boolean;
servePlainDns: boolean;
certificateChain: string;
privateKey: string;
certificatePath: string;
privateKeyPath: string;
change: (...args: unknown[]) => unknown;
submitting: boolean;
invalid: boolean;
initialValues: object;
processingConfig: boolean;
processingValidate: boolean;
status_key?: string;
not_after?: string;
warning_validation?: string;
valid_chain?: boolean;
valid_key?: boolean;
valid_cert?: boolean;
valid_pair?: boolean;
dns_names?: string[];
key_type?: string;
issuer?: string;
subject?: string;
t: (...args: unknown[]) => string;
setTlsConfig: (...args: unknown[]) => unknown;
validateTlsConfig: (...args: unknown[]) => unknown;
certificateSource?: string;
privateKeySource?: string;
privateKeySaved?: boolean;
}
let Form = (props: FormProps) => {
const {
t,
handleSubmit,
@@ -137,9 +181,11 @@ let Form = (props) => {
onChange={handleChange}
/>
</div>
<div className="form__desc">
<Trans>encryption_enable_desc</Trans>
</div>
<div className="form__group mb-3 mt-5">
<Field
name="serve_plain_dns"
@@ -150,16 +196,20 @@ let Form = (props) => {
validate={validatePlainDns}
/>
</div>
<div className="form__desc">
<Trans>encryption_plain_dns_desc</Trans>
</div>
<hr />
</div>
<div className="col-12">
<label className="form__label" htmlFor="server_name">
<Trans>encryption_server</Trans>
</label>
</div>
<div className="col-lg-6">
<div className="form__group form__group--settings">
<Field
@@ -173,11 +223,13 @@ let Form = (props) => {
disabled={!isEnabled}
validate={validateServerName}
/>
<div className="form__desc">
<Trans>encryption_server_desc</Trans>
</div>
</div>
</div>
<div className="col-lg-6">
<div className="form__group form__group--settings">
<Field
@@ -188,18 +240,21 @@ let Form = (props) => {
onChange={handleChange}
disabled={!isEnabled}
/>
<div className="form__desc">
<Trans>encryption_redirect_desc</Trans>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-6">
<div className="form__group form__group--settings">
<label className="form__label" htmlFor="port_https">
<Trans>encryption_https</Trans>
</label>
<Field
id="port_https"
name="port_https"
@@ -212,16 +267,19 @@ let Form = (props) => {
onChange={handleChange}
disabled={!isEnabled}
/>
<div className="form__desc">
<Trans>encryption_https_desc</Trans>
</div>
</div>
</div>
<div className="col-lg-6">
<div className="form__group form__group--settings">
<label className="form__label" htmlFor="port_dns_over_tls">
<Trans>encryption_dot</Trans>
</label>
<Field
id="port_dns_over_tls"
name="port_dns_over_tls"
@@ -234,16 +292,19 @@ let Form = (props) => {
onChange={handleChange}
disabled={!isEnabled}
/>
<div className="form__desc">
<Trans>encryption_dot_desc</Trans>
</div>
</div>
</div>
<div className="col-lg-6">
<div className="form__group form__group--settings">
<label className="form__label" htmlFor="port_dns_over_quic">
<Trans>encryption_doq</Trans>
</label>
<Field
id="port_dns_over_quic"
name="port_dns_over_quic"
@@ -256,30 +317,35 @@ let Form = (props) => {
onChange={handleChange}
disabled={!isEnabled}
/>
<div className="form__desc">
<Trans>encryption_doq_desc</Trans>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-12">
<div className="form__group form__group--settings">
<label
className="form__label form__label--with-desc form__label--bold"
htmlFor="certificate_chain"
>
htmlFor="certificate_chain">
<Trans>encryption_certificates</Trans>
</label>
<div className="form__desc form__desc--top">
<Trans
values={{ link: 'letsencrypt.org' }}
components={[
<a target="_blank" rel="noopener noreferrer" href="https://letsencrypt.org/" key="0">
<a
target="_blank"
rel="noopener noreferrer"
href="https://letsencrypt.org/"
key="0">
link
</a>,
]}
>
]}>
encryption_certificates_desc
</Trans>
</div>
@@ -295,6 +361,7 @@ let Form = (props) => {
placeholder={t('encryption_certificates_source_path')}
disabled={!isEnabled}
/>
<Field
name="certificate_source"
component={renderRadioField}
@@ -332,6 +399,7 @@ let Form = (props) => {
/>
)}
</div>
<div className="form__status">
{(certificateChain || certificatePath) && (
<CertificateStatus
@@ -346,6 +414,7 @@ let Form = (props) => {
</div>
</div>
</div>
<div className="row">
<div className="col-12">
<div className="form__group form__group--settings mt-3">
@@ -364,6 +433,7 @@ let Form = (props) => {
placeholder={t('encryption_key_source_path')}
disabled={!isEnabled}
/>
<Field
name="key_source"
component={renderRadioField}
@@ -396,7 +466,7 @@ let Form = (props) => {
component={CheckboxField}
disabled={!isEnabled}
placeholder={t('use_saved_key')}
onChange={(event) => {
onChange={(event: any) => {
if (event.target.checked) {
change('private_key', '');
}
@@ -405,6 +475,7 @@ let Form = (props) => {
}
}}
/>,
<Field
id="private_key"
key="private_key"
@@ -418,29 +489,24 @@ let Form = (props) => {
/>,
]}
</div>
<div className="form__status">
{(privateKey || privateKeyPath) && (
<KeyStatus validKey={valid_key} keyType={key_type} />
)}
{(privateKey || privateKeyPath) && <KeyStatus validKey={valid_key} keyType={key_type} />}
</div>
</div>
{validationMessage(warning_validation, isWarning)}
</div>
<div className="btn-list mt-2">
<button
type="submit"
disabled={isDisabled}
className="btn btn-success btn-standart"
>
<button type="submit" disabled={isDisabled} className="btn btn-success btn-standart">
<Trans>save_config</Trans>
</button>
<button
type="button"
className="btn btn-secondary btn-standart"
disabled={submitting || processingConfig}
onClick={() => clearFields(change, setTlsConfig, validateTlsConfig, t)}
>
onClick={() => clearFields(change, setTlsConfig, validateTlsConfig, t)}>
<Trans>reset_settings</Trans>
</button>
</div>
@@ -448,40 +514,6 @@ let Form = (props) => {
);
};
Form.propTypes = {
handleSubmit: PropTypes.func.isRequired,
handleChange: PropTypes.func,
isEnabled: PropTypes.bool.isRequired,
servePlainDns: PropTypes.bool.isRequired,
certificateChain: PropTypes.string.isRequired,
privateKey: PropTypes.string.isRequired,
certificatePath: PropTypes.string.isRequired,
privateKeyPath: PropTypes.string.isRequired,
change: PropTypes.func.isRequired,
submitting: PropTypes.bool.isRequired,
invalid: PropTypes.bool.isRequired,
initialValues: PropTypes.object.isRequired,
processingConfig: PropTypes.bool.isRequired,
processingValidate: PropTypes.bool.isRequired,
status_key: PropTypes.string,
not_after: PropTypes.string,
warning_validation: PropTypes.string,
valid_chain: PropTypes.bool,
valid_key: PropTypes.bool,
valid_cert: PropTypes.bool,
valid_pair: PropTypes.bool,
dns_names: PropTypes.arrayOf(PropTypes.string),
key_type: PropTypes.string,
issuer: PropTypes.string,
subject: PropTypes.string,
t: PropTypes.func.isRequired,
setTlsConfig: PropTypes.func.isRequired,
validateTlsConfig: PropTypes.func.isRequired,
certificateSource: PropTypes.string,
privateKeySource: PropTypes.string,
privateKeySaved: PropTypes.bool,
};
const selector = formValueSelector(FORM_NAME.ENCRYPTION);
Form = connect((state) => {

View File

@@ -1,31 +1,27 @@
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { withTranslation, Trans } from 'react-i18next';
const KeyStatus = ({ validKey, keyType }) => (
interface KeyStatusProps {
validKey: boolean;
keyType: string;
}
const KeyStatus = ({ validKey, keyType }: KeyStatusProps) => (
<Fragment>
<div className="form__label form__label--bold">
<Trans>encryption_status</Trans>:
</div>
<ul className="encryption__list">
<li className={validKey ? 'text-success' : 'text-danger'}>
{validKey ? (
<Trans values={{ type: keyType }}>
encryption_key_valid
</Trans>
<Trans values={{ type: keyType }}>encryption_key_valid</Trans>
) : (
<Trans values={{ type: keyType }}>
encryption_key_invalid
</Trans>
<Trans values={{ type: keyType }}>encryption_key_invalid</Trans>
)}
</li>
</ul>
</Fragment>
);
KeyStatus.propTypes = {
validKey: PropTypes.bool.isRequired,
keyType: PropTypes.string.isRequired,
};
export default withTranslation()(KeyStatus);

View File

@@ -1,15 +1,26 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withTranslation } from 'react-i18next';
import debounce from 'lodash/debounce';
import { DEBOUNCE_TIMEOUT, ENCRYPTION_SOURCE } from '../../../helpers/constants';
import Form from './Form';
import Card from '../../ui/Card';
import PageTitle from '../../ui/PageTitle';
import Loading from '../../ui/Loading';
class Encryption extends Component {
import Form from './Form';
import Card from '../../ui/Card';
import PageTitle from '../../ui/PageTitle';
import Loading from '../../ui/Loading';
import { EncryptionData } from '../../../initialState';
interface EncryptionProps {
setTlsConfig: (...args: unknown[]) => unknown;
validateTlsConfig: (...args: unknown[]) => unknown;
encryption: EncryptionData;
t: (...args: unknown[]) => string;
}
class Encryption extends Component<EncryptionProps> {
componentDidMount() {
const { validateTlsConfig, encryption } = this.props;
@@ -18,27 +29,24 @@ class Encryption extends Component {
}
}
handleFormSubmit = (values) => {
handleFormSubmit = (values: any) => {
const submitValues = this.getSubmitValues(values);
this.props.setTlsConfig(submitValues);
};
handleFormChange = debounce((values) => {
const submitValues = this.getSubmitValues(values);
if (submitValues.enabled || submitValues.serve_plain_dns) {
if (submitValues.enabled) {
this.props.validateTlsConfig(submitValues);
}
}, DEBOUNCE_TIMEOUT);
getInitialValues = (data) => {
getInitialValues = (data: any) => {
const { certificate_chain, private_key, private_key_saved } = data;
const certificate_source = certificate_chain
? ENCRYPTION_SOURCE.CONTENT
: ENCRYPTION_SOURCE.PATH;
const key_source = private_key || private_key_saved
? ENCRYPTION_SOURCE.CONTENT
: ENCRYPTION_SOURCE.PATH;
const certificate_source = certificate_chain ? ENCRYPTION_SOURCE.CONTENT : ENCRYPTION_SOURCE.PATH;
const key_source = private_key || private_key_saved ? ENCRYPTION_SOURCE.CONTENT : ENCRYPTION_SOURCE.PATH;
return {
...data,
@@ -47,10 +55,8 @@ class Encryption extends Component {
};
};
getSubmitValues = (values) => {
const {
certificate_source, key_source, private_key_saved, ...config
} = values;
getSubmitValues = (values: any) => {
const { certificate_source, key_source, private_key_saved, ...config } = values;
if (certificate_source === ENCRYPTION_SOURCE.PATH) {
config.certificate_chain = '';
@@ -107,13 +113,13 @@ class Encryption extends Component {
return (
<div className="encryption">
<PageTitle title={t('encryption_settings')} />
{encryption.processing && <Loading />}
{!encryption.processing && (
<Card
title={t('encryption_title')}
subtitle={t('encryption_desc')}
bodyType="card-body box-body--settings"
>
bodyType="card-body box-body--settings">
<Form
initialValues={initialValues}
onSubmit={this.handleFormSubmit}
@@ -129,11 +135,4 @@ class Encryption extends Component {
}
}
Encryption.propTypes = {
setTlsConfig: PropTypes.func.isRequired,
validateTlsConfig: PropTypes.func.isRequired,
encryption: PropTypes.object.isRequired,
t: PropTypes.func.isRequired,
};
export default withTranslation()(Encryption);