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,372 +0,0 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Trans, useTranslation } from 'react-i18next';
import i18next from 'i18next';
import { useSelector } from 'react-redux';
import { MOBILE_CONFIG_LINKS } from '../../../helpers/constants';
import Tabs from '../Tabs';
import MobileConfigForm from './MobileConfigForm';
const renderLi = ({ label, components }) => <li key={label}>
<Trans components={components?.map((props) => {
if (React.isValidElement(props)) {
return props;
}
const {
// eslint-disable-next-line react/prop-types
href, target = '_blank', rel = 'noopener noreferrer', key = '0',
} = props;
return <a href={href} target={target} rel={rel} key={key}>link</a>;
})}>
{label}
</Trans>
</li>;
const getDnsPrivacyList = () => [
{
title: 'Android',
list: [
{
label: 'setup_dns_privacy_android_1',
},
{
label: 'setup_dns_privacy_android_2',
components: [
{
key: 0,
href: 'https://link.adtidy.org/forward.html?action=android&from=ui&app=home',
},
<code key="1">text</code>,
],
},
{
label: 'setup_dns_privacy_android_3',
components: [
{
key: 0,
href: 'https://getintra.org/',
},
<code key="1">text</code>,
],
},
],
},
{
title: 'iOS',
list: [
{
label: 'setup_dns_privacy_ios_2',
components: [
{
key: 0,
href: 'https://link.adtidy.org/forward.html?action=ios&from=ui&app=home',
},
<code key="1">text</code>,
],
},
{
label: 'setup_dns_privacy_ios_1',
components: [
{
key: 0,
href: 'https://itunes.apple.com/app/id1452162351',
},
<code key="1">text</code>,
{
key: 2,
href: 'https://dnscrypt.info/stamps',
},
],
},
],
},
{
title: 'setup_dns_privacy_other_title',
list: [
{
label: 'setup_dns_privacy_other_1',
},
{
label: 'setup_dns_privacy_other_2',
components: [
{
key: 0,
href: 'https://github.com/AdguardTeam/dnsproxy',
},
],
},
{
href: 'https://github.com/jedisct1/dnscrypt-proxy',
label: 'setup_dns_privacy_other_3',
components: [
{
key: 0,
href: 'https://github.com/jedisct1/dnscrypt-proxy',
},
<code key="1">text</code>,
],
},
{
label: 'setup_dns_privacy_other_4',
components: [
{
key: 0,
href: 'https://support.mozilla.org/kb/firefox-dns-over-https',
},
<code key="1">text</code>,
],
},
{
label: 'setup_dns_privacy_other_5',
components: [
{
key: 0,
href: 'https://dnscrypt.info/implementations',
},
{
key: 1,
href: 'https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Clients',
},
],
},
],
},
];
const renderDnsPrivacyList = ({ title, list }) => (
<div className="tab__paragraph" key={title}>
<strong>
<Trans>{title}</Trans>
</strong>
<ul>
{list.map(({ label, components, renderComponent = renderLi }) => (
renderComponent({ label, components })
))}
</ul>
</div>
);
const getTabs = ({
tlsAddress,
httpsAddress,
showDnsPrivacyNotice,
serverName,
portHttps,
t,
}) => ({
Router: {
// eslint-disable-next-line react/display-name
getTitle: () => <p>
<Trans>install_devices_router_desc</Trans>
</p>,
title: 'Router',
list: ['install_devices_router_list_1',
'install_devices_router_list_2',
'install_devices_router_list_3',
// eslint-disable-next-line react/jsx-key
<Trans components={[
<a href="#dhcp" key="0">
link
</a>,
]}>install_devices_router_list_4</Trans>,
],
},
Windows: {
title: 'Windows',
list: ['install_devices_windows_list_1',
'install_devices_windows_list_2',
'install_devices_windows_list_3',
'install_devices_windows_list_4',
'install_devices_windows_list_5',
'install_devices_windows_list_6'],
},
macOS: {
title: 'macOS',
list: ['install_devices_macos_list_1',
'install_devices_macos_list_2',
'install_devices_macos_list_3',
'install_devices_macos_list_4'],
},
Android: {
title: 'Android',
list: ['install_devices_android_list_1',
'install_devices_android_list_2',
'install_devices_android_list_3',
'install_devices_android_list_4',
'install_devices_android_list_5'],
},
iOS: {
title: 'iOS',
list: ['install_devices_ios_list_1',
'install_devices_ios_list_2',
'install_devices_ios_list_3',
'install_devices_ios_list_4'],
},
dns_privacy: {
title: 'dns_privacy',
getTitle: function Title() {
return <div label="dns_privacy" title={t('dns_privacy')}>
<div className="tab__text">
{tlsAddress?.length > 0 && (
<div className="tab__paragraph">
<Trans
values={{ address: tlsAddress[0] }}
components={[
<strong key="0">text</strong>,
<code key="1">text</code>,
]}
>
setup_dns_privacy_1
</Trans>
</div>
)}
{httpsAddress?.length > 0 && (
<div className="tab__paragraph">
<Trans
values={{ address: httpsAddress[0] }}
components={[
<strong key="0">text</strong>,
<code key="1">text</code>,
]}
>
setup_dns_privacy_2
</Trans>
</div>
)}
{showDnsPrivacyNotice ? (
<div className="tab__paragraph">
<Trans
components={[
<a
href="https://github.com/AdguardTeam/AdguardHome/wiki/Encryption"
target="_blank"
rel="noopener noreferrer"
key="0"
>
link
</a>,
<code key="1">text</code>,
]}
>
setup_dns_notice
</Trans>
</div>
) : (
<>
<div className="tab__paragraph">
<Trans components={[<p key="0">text</p>]}>
setup_dns_privacy_3
</Trans>
</div>
{getDnsPrivacyList().map(renderDnsPrivacyList)}
<div>
<strong>
<Trans>
setup_dns_privacy_ioc_mac
</Trans>
</strong>
</div>
<div className="mb-3">
<Trans components={{ highlight: <code /> }}>
setup_dns_privacy_4
</Trans>
</div>
<MobileConfigForm
initialValues={{
host: serverName,
clientId: '',
protocol: MOBILE_CONFIG_LINKS.DOH,
port: portHttps,
}}
/>
</>
)}
</div>
</div>;
},
},
});
const renderContent = ({ title, list, getTitle }) => (
<div key={title} label={i18next.t(title)}>
<div className="tab__title">
{i18next.t(title)}
</div>
<div className="tab__text">
{getTitle?.()}
{list && (
<ol>
{list.map((item) => (
<li key={item}>
<Trans>{item}</Trans>
</li>
))}
</ol>
)}
</div>
</div>
);
const Guide = ({ dnsAddresses }) => {
const { t } = useTranslation();
const serverName = useSelector((state) => state.encryption?.server_name);
const portHttps = useSelector((state) => state.encryption?.port_https);
const tlsAddress = dnsAddresses?.filter((item) => item.includes('tls://')) ?? '';
const httpsAddress = dnsAddresses?.filter((item) => item.includes('https://')) ?? '';
const showDnsPrivacyNotice = httpsAddress.length < 1 && tlsAddress.length < 1;
const [activeTabLabel, setActiveTabLabel] = useState('Router');
const tabs = getTabs({
tlsAddress,
httpsAddress,
showDnsPrivacyNotice,
serverName,
portHttps,
t,
});
const activeTab = renderContent(tabs[activeTabLabel]);
return (
<div>
<Tabs
tabs={tabs}
activeTabLabel={activeTabLabel}
setActiveTabLabel={setActiveTabLabel}
>
{activeTab}
</Tabs>
</div>
);
};
Guide.defaultProps = {
dnsAddresses: [],
};
Guide.propTypes = {
dnsAddresses: PropTypes.array,
};
renderDnsPrivacyList.propTypes = {
title: PropTypes.string.isRequired,
list: PropTypes.array.isRequired,
renderList: PropTypes.func,
};
renderContent.propTypes = {
title: PropTypes.string.isRequired,
list: PropTypes.array.isRequired,
getTitle: PropTypes.func,
};
renderLi.propTypes = {
label: PropTypes.string,
components: PropTypes.string,
};
export default Guide;

View File

@@ -0,0 +1,385 @@
import React, { useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import i18next from 'i18next';
import { useSelector } from 'react-redux';
import { MOBILE_CONFIG_LINKS } from '../../../helpers/constants';
import Tabs from '../Tabs';
import MobileConfigForm from './MobileConfigForm';
import { RootState } from '../../../initialState';
interface renderLiProps {
label?: string;
components?: JSX.Element[];
}
const renderLi = ({ label, components }: renderLiProps) => (
<li key={label}>
<Trans
components={components?.map((props: any) => {
if (React.isValidElement(props)) {
return props;
}
const {
// eslint-disable-next-line react/prop-types
href,
target = '_blank',
rel = 'noopener noreferrer',
key = '0',
} = props;
return (
<a href={href} target={target} rel={rel} key={key}>
link
</a>
);
})}>
{label}
</Trans>
</li>
);
const getDnsPrivacyList = () => [
{
title: 'Android',
list: [
{
label: 'setup_dns_privacy_android_1',
},
{
label: 'setup_dns_privacy_android_2',
components: [
{
key: 0,
href: 'https://link.adtidy.org/forward.html?action=android&from=ui&app=home',
},
<code key="1">text</code>,
],
},
{
label: 'setup_dns_privacy_android_3',
components: [
{
key: 0,
href: 'https://getintra.org/',
},
<code key="1">text</code>,
],
},
],
},
{
title: 'iOS',
list: [
{
label: 'setup_dns_privacy_ios_2',
components: [
{
key: 0,
href: 'https://link.adtidy.org/forward.html?action=ios&from=ui&app=home',
},
<code key="1">text</code>,
],
},
{
label: 'setup_dns_privacy_ios_1',
components: [
{
key: 0,
href: 'https://itunes.apple.com/app/id1452162351',
},
<code key="1">text</code>,
{
key: 2,
href: 'https://dnscrypt.info/stamps',
},
],
},
],
},
{
title: 'setup_dns_privacy_other_title',
list: [
{
label: 'setup_dns_privacy_other_1',
},
{
label: 'setup_dns_privacy_other_2',
components: [
{
key: 0,
href: 'https://github.com/AdguardTeam/dnsproxy',
},
],
},
{
href: 'https://github.com/jedisct1/dnscrypt-proxy',
label: 'setup_dns_privacy_other_3',
components: [
{
key: 0,
href: 'https://github.com/jedisct1/dnscrypt-proxy',
},
<code key="1">text</code>,
],
},
{
label: 'setup_dns_privacy_other_4',
components: [
{
key: 0,
href: 'https://support.mozilla.org/kb/firefox-dns-over-https',
},
<code key="1">text</code>,
],
},
{
label: 'setup_dns_privacy_other_5',
components: [
{
key: 0,
href: 'https://dnscrypt.info/implementations',
},
{
key: 1,
href: 'https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Clients',
},
],
},
],
},
];
interface renderDnsPrivacyListProps {
title: string;
list: unknown[];
renderList?: (...args: unknown[]) => string;
}
const renderDnsPrivacyList = ({ title, list }: renderDnsPrivacyListProps) => (
<div className="tab__paragraph" key={title}>
<strong>
<Trans>{title}</Trans>
</strong>
<ul>
{list.map(({ label, components, renderComponent = renderLi }: any) =>
renderComponent({ label, components }),
)}
</ul>
</div>
);
const getTabs = ({ tlsAddress, httpsAddress, showDnsPrivacyNotice, serverName, portHttps, t }: any) => ({
Router: {
// eslint-disable-next-line react/display-name
getTitle: () => (
<p>
<Trans>install_devices_router_desc</Trans>
</p>
),
title: 'Router',
list: [
'install_devices_router_list_1',
'install_devices_router_list_2',
'install_devices_router_list_3',
// eslint-disable-next-line react/jsx-key
<Trans
components={[
<a href="#dhcp" key="0">
link
</a>,
]}>
install_devices_router_list_4
</Trans>,
],
},
Windows: {
title: 'Windows',
list: [
'install_devices_windows_list_1',
'install_devices_windows_list_2',
'install_devices_windows_list_3',
'install_devices_windows_list_4',
'install_devices_windows_list_5',
'install_devices_windows_list_6',
],
},
macOS: {
title: 'macOS',
list: [
'install_devices_macos_list_1',
'install_devices_macos_list_2',
'install_devices_macos_list_3',
'install_devices_macos_list_4',
],
},
Android: {
title: 'Android',
list: [
'install_devices_android_list_1',
'install_devices_android_list_2',
'install_devices_android_list_3',
'install_devices_android_list_4',
'install_devices_android_list_5',
],
},
iOS: {
title: 'iOS',
list: [
'install_devices_ios_list_1',
'install_devices_ios_list_2',
'install_devices_ios_list_3',
'install_devices_ios_list_4',
],
},
dns_privacy: {
title: 'dns_privacy',
getTitle: function Title() {
return (
<div title={t('dns_privacy')}>
<div className="tab__text">
{tlsAddress?.length > 0 && (
<div className="tab__paragraph">
<Trans
values={{ address: tlsAddress[0] }}
components={[<strong key="0">text</strong>, <code key="1">text</code>]}>
setup_dns_privacy_1
</Trans>
</div>
)}
{httpsAddress?.length > 0 && (
<div className="tab__paragraph">
<Trans
values={{ address: httpsAddress[0] }}
components={[<strong key="0">text</strong>, <code key="1">text</code>]}>
setup_dns_privacy_2
</Trans>
</div>
)}
{showDnsPrivacyNotice ? (
<div className="tab__paragraph">
<Trans
components={[
<a
href="https://github.com/AdguardTeam/AdguardHome/wiki/Encryption"
target="_blank"
rel="noopener noreferrer"
key="0">
link
</a>,
<code key="1">text</code>,
]}>
setup_dns_notice
</Trans>
</div>
) : (
<>
<div className="tab__paragraph">
<Trans components={[<p key="0">text</p>]}>setup_dns_privacy_3</Trans>
</div>
{getDnsPrivacyList().map(renderDnsPrivacyList)}
<div>
<strong>
<Trans>setup_dns_privacy_ioc_mac</Trans>
</strong>
</div>
<div className="mb-3">
<Trans components={{ highlight: <code /> }}>setup_dns_privacy_4</Trans>
</div>
<MobileConfigForm
initialValues={{
host: serverName,
clientId: '',
protocol: MOBILE_CONFIG_LINKS.DOH,
port: portHttps,
}}
/>
</>
)}
</div>
</div>
);
},
},
});
interface renderContentProps {
title: string;
list: unknown[];
getTitle?: (...args: unknown[]) => unknown;
}
const renderContent = ({ title, list, getTitle }: renderContentProps) => (
<div title={i18next.t(title)}>
<div className="tab__title">{i18next.t(title)}</div>
<div className="tab__text">
{getTitle?.()}
{list && (
<ol>
{list.map((item: any) => (
<li key={item}>
<Trans>{item}</Trans>
</li>
))}
</ol>
)}
</div>
</div>
);
interface GuideProps {
dnsAddresses?: unknown[];
}
const Guide = ({ dnsAddresses }: GuideProps) => {
const { t } = useTranslation();
const serverName = useSelector((state: RootState) => state.encryption?.server_name);
const portHttps = useSelector((state: RootState) => state.encryption?.port_https);
const tlsAddress = dnsAddresses?.filter((item: any) => item.includes('tls://')) ?? '';
const httpsAddress = dnsAddresses?.filter((item: any) => item.includes('https://')) ?? '';
const showDnsPrivacyNotice = httpsAddress.length < 1 && tlsAddress.length < 1;
const [activeTabLabel, setActiveTabLabel] = useState('Router');
const tabs = getTabs({
tlsAddress,
httpsAddress,
showDnsPrivacyNotice,
serverName,
portHttps,
t,
});
const activeTab = renderContent(tabs[activeTabLabel]);
return (
<div>
<Tabs tabs={tabs} activeTabLabel={activeTabLabel} setActiveTabLabel={setActiveTabLabel}>
{activeTab}
</Tabs>
</div>
);
};
Guide.defaultProps = {
dnsAddresses: [],
};
export default Guide;

View File

@@ -1,43 +1,32 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Trans } from 'react-i18next';
import { useSelector } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
import i18next from 'i18next';
import cn from 'classnames';
import { getPathWithQueryString } from '../../../helpers/helpers';
import {
CLIENT_ID_LINK,
FORM_NAME,
MOBILE_CONFIG_LINKS,
STANDARD_HTTPS_PORT,
} from '../../../helpers/constants';
import {
renderInputField,
renderSelectField,
toNumber,
} from '../../../helpers/form';
import { CLIENT_ID_LINK, FORM_NAME, MOBILE_CONFIG_LINKS, STANDARD_HTTPS_PORT } from '../../../helpers/constants';
import { renderInputField, renderSelectField, toNumber } from '../../../helpers/form';
import {
validateConfigClientId,
validateServerName,
validatePort,
validateIsSafePort,
} from '../../../helpers/validators';
import { RootState } from '../../../initialState';
const getDownloadLink = (host, clientId, protocol, invalid) => {
const getDownloadLink = (host: any, clientId: any, protocol: any, invalid: any) => {
if (!host || invalid) {
return (
<button
type="button"
className="btn btn-success btn-standard btn-large disabled"
>
<button type="button" className="btn btn-success btn-standard btn-large disabled">
<Trans>download_mobileconfig</Trans>
</button>
);
}
const linkParams = { host };
const linkParams: { host: string, client_id?: string } = { host };
if (clientId) {
linkParams.client_id = clientId;
@@ -47,39 +36,33 @@ const getDownloadLink = (host, clientId, protocol, invalid) => {
<a
href={getPathWithQueryString(protocol, linkParams)}
className={cn('btn btn-success btn-standard btn-large')}
download
>
download>
<Trans>download_mobileconfig</Trans>
</a>
);
};
const MobileConfigForm = ({ invalid }) => {
const formValues = useSelector((state) => state.form[FORM_NAME.MOBILE_CONFIG]?.values);
interface MobileConfigFormProps {
invalid: boolean;
}
const MobileConfigForm = ({ invalid }: MobileConfigFormProps) => {
const formValues = useSelector((state: RootState) => state.form[FORM_NAME.MOBILE_CONFIG]?.values);
if (!formValues) {
return null;
}
const {
host, clientId, protocol, port,
} = formValues;
const { host, clientId, protocol, port } = formValues;
const githubLink = (
<a
href={CLIENT_ID_LINK}
target="_blank"
rel="noopener noreferrer"
>
<a href={CLIENT_ID_LINK} target="_blank" rel="noopener noreferrer">
text
</a>
);
const getHostName = () => {
if (port
&& port !== STANDARD_HTTPS_PORT
&& protocol === MOBILE_CONFIG_LINKS.DOH
) {
if (port && port !== STANDARD_HTTPS_PORT && protocol === MOBILE_CONFIG_LINKS.DOH) {
return `${host}:${port}`;
}
@@ -95,6 +78,7 @@ const MobileConfigForm = ({ invalid }) => {
<label htmlFor="host" className="form__label">
{i18next.t('dhcp_table_hostname')}
</label>
<Field
name="host"
type="text"
@@ -109,6 +93,7 @@ const MobileConfigForm = ({ invalid }) => {
<label htmlFor="port" className="form__label">
{i18next.t('encryption_https')}
</label>
<Field
name="port"
type="number"
@@ -122,15 +107,16 @@ const MobileConfigForm = ({ invalid }) => {
)}
</div>
</div>
<div className="form__group form__group--settings">
<label htmlFor="clientId" className="form__label form__label--with-desc">
{i18next.t('client_id')}
</label>
<div className="form__desc form__desc--top">
<Trans components={{ a: githubLink }}>
client_id_desc
</Trans>
<Trans components={{ a: githubLink }}>client_id_desc</Trans>
</div>
<Field
name="clientId"
type="text"
@@ -140,22 +126,16 @@ const MobileConfigForm = ({ invalid }) => {
validate={validateConfigClientId}
/>
</div>
<div className="form__group form__group--settings">
<label htmlFor="protocol" className="form__label">
{i18next.t('protocol')}
</label>
<Field
name="protocol"
type="text"
component={renderSelectField}
className="form-control"
>
<option value={MOBILE_CONFIG_LINKS.DOT}>
{i18next.t('dns_over_tls')}
</option>
<option value={MOBILE_CONFIG_LINKS.DOH}>
{i18next.t('dns_over_https')}
</option>
<Field name="protocol" type="text" component={renderSelectField} className="form-control">
<option value={MOBILE_CONFIG_LINKS.DOT}>{i18next.t('dns_over_tls')}</option>
<option value={MOBILE_CONFIG_LINKS.DOH}>{i18next.t('dns_over_https')}</option>
</Field>
</div>
</div>
@@ -165,8 +145,4 @@ const MobileConfigForm = ({ invalid }) => {
);
};
MobileConfigForm.propTypes = {
invalid: PropTypes.bool.isRequired,
};
export default reduxForm({ form: FORM_NAME.MOBILE_CONFIG })(MobileConfigForm);