From 197d07f32ba242e13939e01c6511231b0b6abc5a Mon Sep 17 00:00:00 2001 From: Artem Baskal Date: Wed, 4 Dec 2019 21:52:38 +0300 Subject: [PATCH] + client: handle DNS config --- client/src/__locales/en.json | 9 ++ client/src/actions/dnsConfig.js | 35 +++++ client/src/actions/index.js | 12 +- client/src/api/Api.js | 30 +++-- .../src/components/Settings/DnsConfig/Form.js | 120 ++++++++++++++++++ .../components/Settings/DnsConfig/index.js | 49 +++++++ client/src/components/Settings/index.js | 12 ++ client/src/containers/Settings.js | 6 +- client/src/helpers/constants.js | 6 + client/src/reducers/dnsConfig.js | 36 ++++++ client/src/reducers/index.js | 2 + 11 files changed, 294 insertions(+), 23 deletions(-) create mode 100644 client/src/actions/dnsConfig.js create mode 100644 client/src/components/Settings/DnsConfig/Form.js create mode 100644 client/src/components/Settings/DnsConfig/index.js create mode 100644 client/src/reducers/dnsConfig.js diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 14f353aa..44a64bea 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -187,6 +187,15 @@ "query_log_disabled": "The query log is disabled and can be configured in the <0>settings", "query_log_strict_search": "Use double quotes for strict search", "query_log_retention_confirm": "Are you sure you want to change query log retention? If you decrease the interval value, some data will be lost", + "dns_config": "DNS configuration", + "blocking_mode": "Blocking mode", + "nxdomain": "NXDOMAIN", + "null_ip": "Null IP", + "custom_ip": "Custom IP", + "blocking_ipv4": "Blocking IPv4", + "blocking_ipv6": "Blocking IPv6", + "form_enter_rate_limit": "Enter rate limit", + "rate_limit": "Rate limit", "source_label": "Source", "found_in_known_domain_db": "Found in the known domains database.", "category_label": "Category", diff --git a/client/src/actions/dnsConfig.js b/client/src/actions/dnsConfig.js new file mode 100644 index 00000000..1976613e --- /dev/null +++ b/client/src/actions/dnsConfig.js @@ -0,0 +1,35 @@ +import { createAction } from 'redux-actions'; + +import apiClient from '../api/Api'; +import { addErrorToast, addSuccessToast } from './index'; + +export const getDnsConfigRequest = createAction('GET_DNS_CONFIG_REQUEST'); +export const getDnsConfigFailure = createAction('GET_DNS_CONFIG_FAILURE'); +export const getDnsConfigSuccess = createAction('GET_DNS_CONFIG_SUCCESS'); + +export const getDnsConfig = () => async (dispatch) => { + dispatch(getDnsConfigRequest()); + try { + const data = await apiClient.getDnsConfig(); + dispatch(getDnsConfigSuccess(data)); + } catch (error) { + dispatch(addErrorToast({ error })); + dispatch(getDnsConfigFailure()); + } +}; + +export const setDnsConfigRequest = createAction('SET_DNS_CONFIG_REQUEST'); +export const setDnsConfigFailure = createAction('SET_DNS_CONFIG_FAILURE'); +export const setDnsConfigSuccess = createAction('SET_DNS_CONFIG_SUCCESS'); + +export const setDnsConfig = config => async (dispatch) => { + dispatch(setDnsConfigRequest()); + try { + await apiClient.setDnsConfig(config); + dispatch(addSuccessToast('config_successfully_saved')); + dispatch(setDnsConfigSuccess(config)); + } catch (error) { + dispatch(addErrorToast({ error })); + dispatch(setDnsConfigFailure()); + } +}; diff --git a/client/src/actions/index.js b/client/src/actions/index.js index d01130f6..4583c1ae 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -91,17 +91,9 @@ export const toggleProtectionSuccess = createAction('TOGGLE_PROTECTION_SUCCESS') export const toggleProtection = status => async (dispatch) => { dispatch(toggleProtectionRequest()); - let successMessage = ''; - try { - if (status) { - successMessage = 'disabled_protection'; - await apiClient.disableGlobalProtection(); - } else { - successMessage = 'enabled_protection'; - await apiClient.enableGlobalProtection(); - } - + const successMessage = status ? 'disabled_protection' : 'enabled_protection'; + await apiClient.setDnsConfig({ protection_enabled: !status }); dispatch(addSuccessToast(successMessage)); dispatch(toggleProtectionSuccess()); } catch (error) { diff --git a/client/src/api/Api.js b/client/src/api/Api.js index 2393a89d..77dda64b 100644 --- a/client/src/api/Api.js +++ b/client/src/api/Api.js @@ -30,8 +30,6 @@ class Api { GLOBAL_SET_UPSTREAM_DNS = { path: 'set_upstreams_config', method: 'POST' }; GLOBAL_TEST_UPSTREAM_DNS = { path: 'test_upstream_dns', method: 'POST' }; GLOBAL_VERSION = { path: 'version.json', method: 'POST' }; - GLOBAL_ENABLE_PROTECTION = { path: 'enable_protection', method: 'POST' }; - GLOBAL_DISABLE_PROTECTION = { path: 'disable_protection', method: 'POST' }; GLOBAL_UPDATE = { path: 'update', method: 'POST' }; startGlobalFiltering() { @@ -76,16 +74,6 @@ class Api { return this.makeRequest(path, method, config); } - enableGlobalProtection() { - const { path, method } = this.GLOBAL_ENABLE_PROTECTION; - return this.makeRequest(path, method); - } - - disableGlobalProtection() { - const { path, method } = this.GLOBAL_DISABLE_PROTECTION; - return this.makeRequest(path, method); - } - getUpdate() { const { path, method } = this.GLOBAL_UPDATE; return this.makeRequest(path, method); @@ -546,6 +534,24 @@ class Api { const { path, method } = this.GET_PROFILE; return this.makeRequest(path, method); } + + // DNS config + GET_DNS_CONFIG = { path: 'dns_info', method: 'GET' }; + SET_DNS_CONFIG = { path: 'dns_config', method: 'POST' }; + + getDnsConfig() { + const { path, method } = this.GET_DNS_CONFIG; + return this.makeRequest(path, method); + } + + setDnsConfig(data) { + const { path, method } = this.SET_DNS_CONFIG; + const config = { + data, + headers: { 'Content-Type': 'application/json' }, + }; + return this.makeRequest(path, method, config); + } } const apiClient = new Api(); diff --git a/client/src/components/Settings/DnsConfig/Form.js b/client/src/components/Settings/DnsConfig/Form.js new file mode 100644 index 00000000..4cfdff35 --- /dev/null +++ b/client/src/components/Settings/DnsConfig/Form.js @@ -0,0 +1,120 @@ +import React, { Fragment } from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import { Field, reduxForm, formValueSelector } from 'redux-form'; +import { Trans, withNamespaces } from 'react-i18next'; +import flow from 'lodash/flow'; + +import { renderField, renderRadioField, required, ipv4, ipv6, isPositive, toNumber } from '../../../helpers/form'; +import { BLOCKING_MODES } from '../../../helpers/constants'; + +const getFields = (processing, t) => Object.values(BLOCKING_MODES).map(mode => ( + +)); + +let Form = ({ + handleSubmit, submitting, invalid, processing, blockingMode, t, +}) => ( +
+
+
+
+ + +
+
+
+
+ +
+ {getFields(processing, t)} +
+
+
+ {blockingMode === BLOCKING_MODES.custom_ip && ( + +
+
+ + +
+
+
+
+ + +
+
+
+ )} +
+ +
+); + +Form.propTypes = { + blockingMode: PropTypes.string.isRequired, + handleSubmit: PropTypes.func.isRequired, + submitting: PropTypes.bool.isRequired, + invalid: PropTypes.bool.isRequired, + processing: PropTypes.bool.isRequired, + t: PropTypes.func.isRequired, +}; + +const selector = formValueSelector('blockingModeForm'); + +Form = connect((state) => { + const blockingMode = selector(state, 'blocking_mode'); + return { + blockingMode, + }; +})(Form); + +export default flow([ + withNamespaces(), + reduxForm({ + form: 'blockingModeForm', + }), +])(Form); diff --git a/client/src/components/Settings/DnsConfig/index.js b/client/src/components/Settings/DnsConfig/index.js new file mode 100644 index 00000000..c0f0fca0 --- /dev/null +++ b/client/src/components/Settings/DnsConfig/index.js @@ -0,0 +1,49 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { withNamespaces } from 'react-i18next'; + +import Card from '../../ui/Card'; +import Form from './Form'; + +const DnsConfig = ({ t, dnsConfig, setDnsConfig }) => { + const handleFormSubmit = (values) => { + setDnsConfig(values); + }; + + const { + blocking_mode, + ratelimit, + blocking_ipv4, + blocking_ipv6, + processingSetConfig, + } = dnsConfig; + + return ( + +
+
+
+
+ ); +}; + +DnsConfig.propTypes = { + dnsConfig: PropTypes.object.isRequired, + setDnsConfig: PropTypes.func.isRequired, + t: PropTypes.func.isRequired, +}; + +export default withNamespaces()(DnsConfig); diff --git a/client/src/components/Settings/index.js b/client/src/components/Settings/index.js index 9c05f680..5fcc72cd 100644 --- a/client/src/components/Settings/index.js +++ b/client/src/components/Settings/index.js @@ -6,6 +6,8 @@ import Services from './Services'; import StatsConfig from './StatsConfig'; import LogsConfig from './LogsConfig'; import FiltersConfig from './FiltersConfig'; +import DnsConfig from './DnsConfig'; + import Checkbox from '../ui/Checkbox'; import Loading from '../ui/Loading'; import PageTitle from '../ui/PageTitle'; @@ -38,6 +40,7 @@ class Settings extends Component { this.props.getStatsConfig(); this.props.getLogsConfig(); this.props.getFilteringStatus(); + this.props.getDnsConfig(); } renderSettings = (settings) => { @@ -68,10 +71,12 @@ class Settings extends Component { resetStats, stats, queryLogs, + dnsConfig, setLogsConfig, clearLogs, filtering, setFiltersConfig, + setDnsConfig, t, } = this.props; @@ -101,6 +106,12 @@ class Settings extends Component { +
+ +
{ const { - settings, services, stats, queryLogs, filtering, + settings, services, stats, queryLogs, filtering, dnsConfig, } = state; const props = { settings, @@ -16,6 +17,7 @@ const mapStateToProps = (state) => { stats, queryLogs, filtering, + dnsConfig, }; return props; }; @@ -33,6 +35,8 @@ const mapDispatchToProps = { setLogsConfig, getFilteringStatus, setFiltersConfig, + getDnsConfig, + setDnsConfig, }; export default connect( diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index fefd9425..30076306 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -341,6 +341,12 @@ export const QUERY_LOG_INTERVALS_DAYS = [1, 7, 30, 90]; export const FILTERS_INTERVALS_HOURS = [0, 1, 12, 24, 72, 168]; +export const BLOCKING_MODES = { + nxdomain: 'nxdomain', + null_ip: 'null_ip', + custom_ip: 'custom_ip', +}; + export const WHOIS_ICONS = { location: 'location', orgname: 'network', diff --git a/client/src/reducers/dnsConfig.js b/client/src/reducers/dnsConfig.js new file mode 100644 index 00000000..c2807261 --- /dev/null +++ b/client/src/reducers/dnsConfig.js @@ -0,0 +1,36 @@ +import { handleActions } from 'redux-actions'; + +import * as actions from '../actions/dnsConfig'; +import { BLOCKING_MODES } from '../helpers/constants'; + +const dnsConfig = handleActions( + { + [actions.getDnsConfigRequest]: state => ({ ...state, processingGetConfig: true }), + [actions.getDnsConfigFailure]: state => + ({ ...state, processingGetConfig: false }), + [actions.getDnsConfigSuccess]: (state, { payload }) => ({ + ...state, + ...payload, + processingGetConfig: false, + }), + + [actions.setDnsConfigRequest]: state => ({ ...state, processingSetConfig: true }), + [actions.setDnsConfigFailure]: state => + ({ ...state, processingSetConfig: false }), + [actions.setDnsConfigSuccess]: (state, { payload }) => ({ + ...state, + ...payload, + processingSetConfig: false, + }), + }, + { + processingGetConfig: false, + processingSetConfig: false, + blocking_mode: BLOCKING_MODES.nxdomain, + ratelimit: 20, + blocking_ipv4: '', + blocking_ipv6: '', + }, +); + +export default dnsConfig; diff --git a/client/src/reducers/index.js b/client/src/reducers/index.js index 3eca36a6..0e2b69bb 100644 --- a/client/src/reducers/index.js +++ b/client/src/reducers/index.js @@ -13,6 +13,7 @@ import rewrites from './rewrites'; import services from './services'; import stats from './stats'; import queryLogs from './queryLogs'; +import dnsConfig from './dnsConfig'; import filtering from './filtering'; const settings = handleActions( @@ -369,6 +370,7 @@ export default combineReducers({ rewrites, services, stats, + dnsConfig, loadingBar: loadingBarReducer, form: formReducer, });