From f3b41efff3f2eab3dc0a3683b05bb98f6048f6e0 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Fri, 31 Jan 2020 14:09:04 +0300 Subject: [PATCH 01/10] * http: allow access to /__locales/ while installing --- home/helpers.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/home/helpers.go b/home/helpers.go index c00fcbc8..ec95aa67 100644 --- a/home/helpers.go +++ b/home/helpers.go @@ -111,8 +111,9 @@ func preInstallHandler(handler http.Handler) http.Handler { func postInstall(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { if config.firstRun && - !strings.HasPrefix(r.URL.Path, "/install.") && - r.URL.Path != "/favicon.png" { + !(strings.HasPrefix(r.URL.Path, "/install.") || + strings.HasPrefix(r.URL.Path, "/__locales/") || + r.URL.Path == "/favicon.png") { http.Redirect(w, r, "/install.html", http.StatusSeeOther) // should not be cacheable return } From 2151563757125e25e9ffc971fdbb1b16774f5f2d Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Fri, 31 Jan 2020 14:15:11 +0300 Subject: [PATCH 02/10] + http: allow access to /__locales/ when not authenticated --- home/auth.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/home/auth.go b/home/auth.go index aae40f33..9afe2c87 100644 --- a/home/auth.go +++ b/home/auth.go @@ -379,7 +379,8 @@ func optionalAuth(handler func(http.ResponseWriter, *http.Request)) func(http.Re } } else if r.URL.Path == "/favicon.png" || - strings.HasPrefix(r.URL.Path, "/login.") { + strings.HasPrefix(r.URL.Path, "/login.") || + strings.HasPrefix(r.URL.Path, "/__locales/") { // process as usual } else if config.auth != nil && config.auth.AuthRequired() { From 4d55f51feeb50a8fdf36f1345ba5063b5d27afc5 Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Fri, 31 Jan 2020 15:57:20 +0300 Subject: [PATCH 03/10] + client: remove locales from js bundle --- .twosky.json | 8 +- client/.eslintrc | 5 + client/package-lock.json | 143 ++++++++++++++++++++++++++--- client/package.json | 1 + client/src/components/ui/Footer.js | 10 +- client/src/helpers/constants.js | 111 ---------------------- client/src/helpers/twosky.js | 6 ++ client/src/i18n.js | 127 ++----------------------- client/webpack.common.js | 14 ++- 9 files changed, 177 insertions(+), 248 deletions(-) create mode 100644 client/src/helpers/twosky.js diff --git a/.twosky.json b/.twosky.json index 8ad2a205..c1dcf2f9 100644 --- a/.twosky.json +++ b/.twosky.json @@ -7,29 +7,29 @@ "da": "Dansk", "de": "Deutsch", "nl": "Dutch", - "no": "Norsk", "en": "English", "es": "Español", "fr": "Français", + "hr": "Hrvatski", "id": "Indonesian", "it": "Italiano", + "no": "Norsk", "pl": "Polski", "pt-br": "Portuguese (BR)", "pt-pt": "Portuguese (PT)", "sk": "Slovenčina", "sl": "Slovenščina", + "sr-cs": "Srpski", "sv": "Svenska", "vi": "Tiếng Việt", "tr": "Türkçe", "cs": "Český", "bg": "Български", "ru": "Русский", + "fa": "فارسی", "ja": "日本語", "zh-tw": "正體中文", "zh-cn": "简体中文", - "sr-cs": "Srpski", - "hr": "Hrvatski", - "fa": "فارسی", "ko": "한국어" } } diff --git a/client/.eslintrc b/client/.eslintrc index d5d5955b..56b5a7a6 100644 --- a/client/.eslintrc +++ b/client/.eslintrc @@ -17,6 +17,11 @@ "react": { "pragma": "React", "version": "16.4" + }, + "import/resolver": { + "webpack": { + "config": "webpack.common.js" + } } }, diff --git a/client/package-lock.json b/client/package-lock.json index 81899b0c..d0ec7a06 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -925,6 +925,12 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, + "array-find": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz", + "integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=", + "dev": true + }, "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -4548,6 +4554,79 @@ } } }, + "eslint-import-resolver-webpack": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.12.1.tgz", + "integrity": "sha512-O/sUAXk6GWrICiN8JUkkjdt9uZpqZHP+FVnTxtEILL6EZMaPSrnP4lGPSFwcKsv7O211maqq4Nz60+dh236hVg==", + "dev": true, + "requires": { + "array-find": "^1.0.0", + "debug": "^2.6.9", + "enhanced-resolve": "^0.9.1", + "find-root": "^1.1.0", + "has": "^1.0.3", + "interpret": "^1.2.0", + "lodash": "^4.17.15", + "node-libs-browser": "^1.0.0 || ^2.0.0", + "resolve": "^1.13.1", + "semver": "^5.7.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "enhanced-resolve": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz", + "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.2.0", + "tapable": "^0.1.8" + } + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "memory-fs": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz", + "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=", + "dev": true + }, + "resolve": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.0.tgz", + "integrity": "sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "tapable": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz", + "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=", + "dev": true + } + } + }, "eslint-loader": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-1.9.0.tgz", @@ -5458,7 +5537,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -5479,12 +5559,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5499,17 +5581,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -5626,7 +5711,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5638,6 +5724,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5652,6 +5739,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5659,12 +5747,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5683,6 +5773,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5763,7 +5854,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5775,6 +5867,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -5860,7 +5953,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -5896,6 +5990,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5915,6 +6010,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5958,12 +6054,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -6778,6 +6876,29 @@ "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-2.2.3.tgz", "integrity": "sha512-sJZ2n9Vgax0vGer23hJMwyO3FRO7P0dq2DXZPXWE329g3snfJUcw+S24Mp3lqJaxL/0McDu4BD75ds6pzIfhhw==" }, + "i18next-xhr-backend": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/i18next-xhr-backend/-/i18next-xhr-backend-3.2.2.tgz", + "integrity": "sha512-OtRf2Vo3IqAxsttQbpjYnmMML12IMB5e0fc5B7qKJFLScitYaXa1OhMX0n0X/3vrfFlpHL9Ro/H+ps4Ej2j7QQ==", + "requires": { + "@babel/runtime": "^7.5.5" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.3.tgz", + "integrity": "sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, + "regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/client/package.json b/client/package.json index b2be9b5b..026692eb 100644 --- a/client/package.json +++ b/client/package.json @@ -15,6 +15,7 @@ "date-fns": "^1.29.0", "i18next": "^12.0.0", "i18next-browser-languagedetector": "^2.2.3", + "i18next-xhr-backend": "^3.2.2", "lodash": "^4.17.15", "nanoid": "^1.2.3", "prop-types": "^15.7.2", diff --git a/client/src/components/ui/Footer.js b/client/src/components/ui/Footer.js index b61058d4..8174ba2d 100644 --- a/client/src/components/ui/Footer.js +++ b/client/src/components/ui/Footer.js @@ -1,7 +1,9 @@ import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { Trans, withNamespaces } from 'react-i18next'; -import { REPOSITORY, LANGUAGES, PRIVACY_POLICY_LINK } from '../../helpers/constants'; + +import { REPOSITORY, PRIVACY_POLICY_LINK } from '../../helpers/constants'; +import { LANGUAGES } from '../../helpers/twosky'; import i18n from '../../i18n'; import Version from './Version'; @@ -68,9 +70,9 @@ class Footer extends Component { value={i18n.language} onChange={this.changeLanguage} > - {LANGUAGES.map(language => ( - ))} diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index 5920552c..2c457736 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -31,117 +31,6 @@ export const REPOSITORY = { export const PRIVACY_POLICY_LINK = 'https://adguard.com/privacy/home.html'; -export const LANGUAGES = [ - { - key: 'da', - name: 'Dansk', - }, - { - key: 'de', - name: 'Deutsch', - }, - { - key: 'nl', - name: 'Dutch', - }, - { - key: 'en', - name: 'English', - }, - { - key: 'es', - name: 'Español', - }, - { - key: 'fr', - name: 'Français', - }, - { - key: 'id', - name: 'Indonesian', - }, - { - key: 'it', - name: 'Italiano', - }, - { - key: 'pl', - name: 'Polski', - }, - { - key: 'pt-br', - name: 'Portuguese (BR)', - }, - { - key: 'pt-pt', - name: 'Portuguese (PT)', - }, - { - key: 'sk', - name: 'Slovenčina', - }, - { - key: 'sl', - name: 'Slovenščina', - }, - { - key: 'sv', - name: 'Svenska', - }, - { - key: 'vi', - name: 'Tiếng Việt', - }, - { - key: 'tr', - name: 'Türkçe', - }, - { - key: 'cs', - name: 'Český', - }, - { - key: 'bg', - name: 'Български', - }, - { - key: 'ru', - name: 'Русский', - }, - { - key: 'ja', - name: '日本語', - }, - { - key: 'zh-tw', - name: '正體中文', - }, - { - key: 'zh-cn', - name: '简体中文', - }, - { - key: 'no', - name: 'Norsk', - }, - { - key: 'sr-cs', - name: 'Srpski', - }, - { - key: 'hr', - name: 'Hrvatski', - }, - { - key: 'fa', - name: 'فارسی', - }, - { - key: 'ko', - name: '한국어', - }, -]; - export const INSTALL_FIRST_STEP = 1; export const INSTALL_TOTAL_STEPS = 5; diff --git a/client/src/helpers/twosky.js b/client/src/helpers/twosky.js new file mode 100644 index 00000000..d9534ba6 --- /dev/null +++ b/client/src/helpers/twosky.js @@ -0,0 +1,6 @@ +import twosky from 'MainRoot/.twosky.json'; + +export const { + languages: LANGUAGES, + base_locale: BASE_LOCALE, +} = twosky[0]; diff --git a/client/src/i18n.js b/client/src/i18n.js index 6f13536a..afc3b65b 100644 --- a/client/src/i18n.js +++ b/client/src/i18n.js @@ -1,132 +1,21 @@ import i18n from 'i18next'; +import XHR from 'i18next-xhr-backend'; import { reactI18nextModule } from 'react-i18next'; import { initReactI18n } from 'react-i18next/hooks'; import langDetect from 'i18next-browser-languagedetector'; -import { DEFAULT_LANGUAGE } from './helpers/constants'; +import { LANGUAGES, BASE_LOCALE } from './helpers/twosky'; -import vi from './__locales/vi.json'; -import en from './__locales/en.json'; -import ru from './__locales/ru.json'; -import es from './__locales/es.json'; -import fr from './__locales/fr.json'; -import ja from './__locales/ja.json'; -import sv from './__locales/sv.json'; -import ptBR from './__locales/pt-br.json'; -import zhTW from './__locales/zh-tw.json'; -import bg from './__locales/bg.json'; -import zhCN from './__locales/zh-cn.json'; -import cs from './__locales/cs.json'; -import da from './__locales/da.json'; -import de from './__locales/de.json'; -import id from './__locales/id.json'; -import it from './__locales/it.json'; -import ko from './__locales/ko.json'; -import no from './__locales/no.json'; -import nl from './__locales/nl.json'; -import pl from './__locales/pl.json'; -import ptPT from './__locales/pt-pt.json'; -import sk from './__locales/sk.json'; -import sl from './__locales/sl.json'; -import tr from './__locales/tr.json'; -import srCS from './__locales/sr-cs.json'; -import hr from './__locales/hr.json'; -import fa from './__locales/fa.json'; - -const resources = { - en: { - translation: en, - }, - vi: { - translation: vi, - }, - ru: { - translation: ru, - }, - es: { - translation: es, - }, - fr: { - translation: fr, - }, - ja: { - translation: ja, - }, - sv: { - translation: sv, - }, - 'pt-br': { - translation: ptBR, - }, - 'zh-tw': { - translation: zhTW, - }, - bg: { - translation: bg, - }, - 'zh-cn': { - translation: zhCN, - }, - cs: { - translation: cs, - }, - da: { - translation: da, - }, - de: { - translation: de, - }, - id: { - translation: id, - }, - it: { - translation: it, - }, - ko: { - translation: ko, - }, - no: { - translation: no, - }, - nl: { - translation: nl, - }, - pl: { - translation: pl, - }, - 'pt-pt': { - translation: ptPT, - }, - sk: { - translation: sk, - }, - sl: { - translation: sl, - }, - tr: { - translation: tr, - }, - 'sr-cs': { - translation: srCS, - }, - hr: { - translation: hr, - }, - fa: { - translation: fa, - }, -}; - -const availableLanguages = Object.keys(resources); +const availableLanguages = Object.keys(LANGUAGES); i18n .use(langDetect) + .use(XHR) .use(initReactI18n) .use(reactI18nextModule) .init({ - resources, lowerCaseLng: true, - fallbackLng: DEFAULT_LANGUAGE, + fallbackLng: BASE_LOCALE, keySeparator: false, nsSeparator: false, returnEmptyString: false, @@ -136,9 +25,13 @@ i18n react: { wait: true, }, + whitelist: availableLanguages, + backend: { + loadPath: '/__locales/{{lng}}.json', + }, }, () => { if (!availableLanguages.includes(i18n.language)) { - i18n.changeLanguage(DEFAULT_LANGUAGE); + i18n.changeLanguage(BASE_LOCALE); } }); diff --git a/client/webpack.common.js b/client/webpack.common.js index 32248b14..db61ea17 100644 --- a/client/webpack.common.js +++ b/client/webpack.common.js @@ -15,6 +15,7 @@ const HTML_PATH = path.resolve(RESOURCES_PATH, 'public/index.html'); const HTML_INSTALL_PATH = path.resolve(RESOURCES_PATH, 'public/install.html'); const HTML_LOGIN_PATH = path.resolve(RESOURCES_PATH, 'public/login.html'); const FAVICON_PATH = path.resolve(RESOURCES_PATH, 'public/favicon.png'); +const LOCALES_PATH = path.resolve(RESOURCES_PATH, 'src/__locales/*.json'); const PUBLIC_PATH = path.resolve(__dirname, '../build/static'); @@ -32,6 +33,10 @@ const config = { }, resolve: { modules: ['node_modules'], + alias: { + MainRoot: path.resolve(__dirname, '../'), + ClientRoot: path.resolve(__dirname, './src'), + }, }, module: { rules: [ @@ -101,7 +106,7 @@ const config = { new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), }), - new CleanWebpackPlugin(['*.*'], { + new CleanWebpackPlugin(['**/*.*'], { root: PUBLIC_PATH, verbose: false, dry: false, @@ -132,6 +137,13 @@ const config = { new CopyPlugin([ { from: FAVICON_PATH, to: PUBLIC_PATH }, ]), + new CopyPlugin([ + { + from: LOCALES_PATH, + to: PUBLIC_PATH, + context: 'src/', + }, + ]), ], }; From d633e45a064e94029d5e659efa07aeb685794a8b Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Fri, 31 Jan 2020 16:01:02 +0300 Subject: [PATCH 04/10] + client: add eslint-import-resolver-webpack --- client/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/client/package.json b/client/package.json index 026692eb..39136778 100644 --- a/client/package.json +++ b/client/package.json @@ -55,6 +55,7 @@ "eslint": "^4.19.1", "eslint-config-airbnb-base": "^12.1.0", "eslint-config-react-app": "^2.1.0", + "eslint-import-resolver-webpack": "^0.12.1", "eslint-loader": "1.9.0", "eslint-plugin-import": "^2.12.0", "eslint-plugin-jsx-a11y": "5.1.1", From d062acc149cf5e35ce19baf31e5463a1a294e6e6 Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Mon, 3 Feb 2020 14:17:39 +0300 Subject: [PATCH 05/10] *(global): update trackers db --- client/src/helpers/trackers/adguard.json | 8 +++++++- client/src/helpers/trackers/whotracksme.json | 6 ------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/src/helpers/trackers/adguard.json b/client/src/helpers/trackers/adguard.json index 4cd8aea1..3fb582b1 100644 --- a/client/src/helpers/trackers/adguard.json +++ b/client/src/helpers/trackers/adguard.json @@ -96,6 +96,11 @@ "name": "Microsoft Azure", "categoryId": 10, "url": "https://azure.microsoft.com/" + }, + "button": { + "name": "Button", + "categoryId": 4, + "url": "https://www.usebutton.com/" } }, "trackerDomains": { @@ -119,6 +124,7 @@ "edgecastcdn.net": "markmonitor", "appcenter.ms": "appcenter", "unityads.unity3d.com": "unity_ads", - "azure.com": "azure" + "azure.com": "azure", + "bttn.io": "button" } } \ No newline at end of file diff --git a/client/src/helpers/trackers/whotracksme.json b/client/src/helpers/trackers/whotracksme.json index 1cfac23c..2185a60c 100644 --- a/client/src/helpers/trackers/whotracksme.json +++ b/client/src/helpers/trackers/whotracksme.json @@ -696,11 +696,6 @@ "categoryId": 4, "url": "http://adgoto.com/" }, - "adguard": { - "name": "Adguard", - "categoryId": 12, - "url": "https://adguard.com/" - }, "adhands": { "name": "AdHands", "categoryId": 4, @@ -16201,7 +16196,6 @@ "smartredirect.de": "adgoal", "adgorithms.com": "adgorithms", "adgoto.com": "adgoto", - "adguard.com": "adguard", "adhands.ru": "adhands", "adhese.be": "adhese", "adhese.com": "adhese", From ee5456cf8c7cf2d4513d6ee0e6a205cfb987634f Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Tue, 4 Feb 2020 13:37:35 +0300 Subject: [PATCH 06/10] Revert remove locales from js bundle --- client/package-lock.json | 23 -------- client/package.json | 1 - client/src/i18n.js | 118 +++++++++++++++++++++++++++++++++++++-- client/webpack.common.js | 8 --- 4 files changed, 113 insertions(+), 37 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index d0ec7a06..e8732e57 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -6876,29 +6876,6 @@ "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-2.2.3.tgz", "integrity": "sha512-sJZ2n9Vgax0vGer23hJMwyO3FRO7P0dq2DXZPXWE329g3snfJUcw+S24Mp3lqJaxL/0McDu4BD75ds6pzIfhhw==" }, - "i18next-xhr-backend": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/i18next-xhr-backend/-/i18next-xhr-backend-3.2.2.tgz", - "integrity": "sha512-OtRf2Vo3IqAxsttQbpjYnmMML12IMB5e0fc5B7qKJFLScitYaXa1OhMX0n0X/3vrfFlpHL9Ro/H+ps4Ej2j7QQ==", - "requires": { - "@babel/runtime": "^7.5.5" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.3.tgz", - "integrity": "sha512-fVHx1rzEmwB130VTkLnxR+HmxcTjGzH12LYQcFFoBwakMd3aOMD4OsRN7tGG/UOYE2ektgFrS8uACAoRk1CY0w==", - "requires": { - "regenerator-runtime": "^0.13.2" - } - }, - "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" - } - } - }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/client/package.json b/client/package.json index 39136778..aadad4b5 100644 --- a/client/package.json +++ b/client/package.json @@ -15,7 +15,6 @@ "date-fns": "^1.29.0", "i18next": "^12.0.0", "i18next-browser-languagedetector": "^2.2.3", - "i18next-xhr-backend": "^3.2.2", "lodash": "^4.17.15", "nanoid": "^1.2.3", "prop-types": "^15.7.2", diff --git a/client/src/i18n.js b/client/src/i18n.js index afc3b65b..066f5707 100644 --- a/client/src/i18n.js +++ b/client/src/i18n.js @@ -1,19 +1,130 @@ import i18n from 'i18next'; -import XHR from 'i18next-xhr-backend'; import { reactI18nextModule } from 'react-i18next'; import { initReactI18n } from 'react-i18next/hooks'; import langDetect from 'i18next-browser-languagedetector'; import { LANGUAGES, BASE_LOCALE } from './helpers/twosky'; +import vi from './__locales/vi.json'; +import en from './__locales/en.json'; +import ru from './__locales/ru.json'; +import es from './__locales/es.json'; +import fr from './__locales/fr.json'; +import ja from './__locales/ja.json'; +import sv from './__locales/sv.json'; +import ptBR from './__locales/pt-br.json'; +import zhTW from './__locales/zh-tw.json'; +import bg from './__locales/bg.json'; +import zhCN from './__locales/zh-cn.json'; +import cs from './__locales/cs.json'; +import da from './__locales/da.json'; +import de from './__locales/de.json'; +import id from './__locales/id.json'; +import it from './__locales/it.json'; +import ko from './__locales/ko.json'; +import no from './__locales/no.json'; +import nl from './__locales/nl.json'; +import pl from './__locales/pl.json'; +import ptPT from './__locales/pt-pt.json'; +import sk from './__locales/sk.json'; +import sl from './__locales/sl.json'; +import tr from './__locales/tr.json'; +import srCS from './__locales/sr-cs.json'; +import hr from './__locales/hr.json'; +import fa from './__locales/fa.json'; + +const resources = { + en: { + translation: en, + }, + vi: { + translation: vi, + }, + ru: { + translation: ru, + }, + es: { + translation: es, + }, + fr: { + translation: fr, + }, + ja: { + translation: ja, + }, + sv: { + translation: sv, + }, + 'pt-br': { + translation: ptBR, + }, + 'zh-tw': { + translation: zhTW, + }, + bg: { + translation: bg, + }, + 'zh-cn': { + translation: zhCN, + }, + cs: { + translation: cs, + }, + da: { + translation: da, + }, + de: { + translation: de, + }, + id: { + translation: id, + }, + it: { + translation: it, + }, + ko: { + translation: ko, + }, + no: { + translation: no, + }, + nl: { + translation: nl, + }, + pl: { + translation: pl, + }, + 'pt-pt': { + translation: ptPT, + }, + sk: { + translation: sk, + }, + sl: { + translation: sl, + }, + tr: { + translation: tr, + }, + 'sr-cs': { + translation: srCS, + }, + hr: { + translation: hr, + }, + fa: { + translation: fa, + }, +}; + const availableLanguages = Object.keys(LANGUAGES); i18n .use(langDetect) - .use(XHR) .use(initReactI18n) .use(reactI18nextModule) .init({ + resources, lowerCaseLng: true, fallbackLng: BASE_LOCALE, keySeparator: false, @@ -26,9 +137,6 @@ i18n wait: true, }, whitelist: availableLanguages, - backend: { - loadPath: '/__locales/{{lng}}.json', - }, }, () => { if (!availableLanguages.includes(i18n.language)) { i18n.changeLanguage(BASE_LOCALE); diff --git a/client/webpack.common.js b/client/webpack.common.js index db61ea17..99b6dbae 100644 --- a/client/webpack.common.js +++ b/client/webpack.common.js @@ -15,7 +15,6 @@ const HTML_PATH = path.resolve(RESOURCES_PATH, 'public/index.html'); const HTML_INSTALL_PATH = path.resolve(RESOURCES_PATH, 'public/install.html'); const HTML_LOGIN_PATH = path.resolve(RESOURCES_PATH, 'public/login.html'); const FAVICON_PATH = path.resolve(RESOURCES_PATH, 'public/favicon.png'); -const LOCALES_PATH = path.resolve(RESOURCES_PATH, 'src/__locales/*.json'); const PUBLIC_PATH = path.resolve(__dirname, '../build/static'); @@ -137,13 +136,6 @@ const config = { new CopyPlugin([ { from: FAVICON_PATH, to: PUBLIC_PATH }, ]), - new CopyPlugin([ - { - from: LOCALES_PATH, - to: PUBLIC_PATH, - context: 'src/', - }, - ]), ], }; From a5c2ad1b2fa52a071beb759d6b673de73a3d4f4d Mon Sep 17 00:00:00 2001 From: Ildar Kamalov Date: Tue, 4 Feb 2020 15:48:07 +0300 Subject: [PATCH 07/10] Merge: - client: block/unblock client without requesting stats Closes #896 Squashed commit of the following: commit 66b781438aa668a16b19455c3e0dc5100417d869 Author: Ildar Kamalov Date: Mon Feb 3 12:59:25 2020 +0300 - client: block/unblock client without requesting stats commit e70f62738d549e32339bae3d5e996a912b99c21d Author: Ildar Kamalov Date: Mon Feb 3 12:22:13 2020 +0300 - client: get current access settings before set commit 65c59d1d55f3255f33f917b61b6ab2c6c2e54271 Author: Ildar Kamalov Date: Mon Feb 3 12:21:12 2020 +0300 * client: mode svg-url-loader to devDependencies --- client/package-lock.json | 30 ++++++++++++++++------ client/package.json | 4 +-- client/src/actions/access.js | 19 ++++++-------- client/src/actions/stats.js | 7 ++--- client/src/components/Dashboard/Clients.js | 16 +++++++----- client/src/components/Dashboard/index.js | 5 +++- client/src/helpers/helpers.js | 11 -------- client/src/reducers/access.js | 16 +++++++++++- 8 files changed, 63 insertions(+), 45 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index e8732e57..0e43676f 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -821,6 +821,7 @@ "version": "6.5.3", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz", "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==", + "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -837,7 +838,8 @@ "ajv-keywords": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true }, "align-text": { "version": "0.1.4", @@ -2278,7 +2280,8 @@ "big.js": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true }, "binary-extensions": { "version": "1.11.0", @@ -4218,7 +4221,8 @@ "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true }, "encodeurl": { "version": "1.0.2", @@ -5231,7 +5235,8 @@ "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true }, "fast-glob": { "version": "2.2.6", @@ -5250,7 +5255,8 @@ "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true }, "fast-levenshtein": { "version": "2.0.6", @@ -7551,7 +7557,8 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -7568,7 +7575,8 @@ "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true }, "jsx-ast-utils": { "version": "1.4.1", @@ -7706,6 +7714,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, "requires": { "big.js": "^3.1.3", "emojis-list": "^2.0.0", @@ -10287,7 +10296,8 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, "q": { "version": "1.5.1", @@ -11137,6 +11147,7 @@ "version": "0.4.7", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "dev": true, "requires": { "ajv": "^6.1.0", "ajv-keywords": "^3.1.0" @@ -12564,6 +12575,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/svg-url-loader/-/svg-url-loader-2.3.2.tgz", "integrity": "sha1-3YaybBn+O5FPBOoQ7zlZTq3gRGQ=", + "dev": true, "requires": { "file-loader": "1.1.11", "loader-utils": "1.1.0" @@ -12573,6 +12585,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.11.tgz", "integrity": "sha512-TGR4HU7HUsGg6GCOPJnFk06RhWgEWFLAGWiT6rcD+GRC2keU3s9RGJ+b3Z6/U73jwwNb2gKLJ7YCrp+jvU4ALg==", + "dev": true, "requires": { "loader-utils": "^1.0.2", "schema-utils": "^0.4.5" @@ -13044,6 +13057,7 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, "requires": { "punycode": "^2.1.0" } diff --git a/client/package.json b/client/package.json index aadad4b5..4ee1c1c3 100644 --- a/client/package.json +++ b/client/package.json @@ -34,7 +34,6 @@ "redux-actions": "^2.4.0", "redux-form": "^7.4.2", "redux-thunk": "^2.3.0", - "svg-url-loader": "^2.3.2", "url-polyfill": "^1.1.7" }, "devDependencies": { @@ -75,6 +74,7 @@ "url-loader": "^1.0.1", "webpack": "3.8.1", "webpack-dev-server": "^3.1.14", - "webpack-merge": "^4.1.3" + "webpack-merge": "^4.1.3", + "svg-url-loader": "^2.3.2" } } diff --git a/client/src/actions/access.js b/client/src/actions/access.js index 1f51cea7..96c661c1 100644 --- a/client/src/actions/access.js +++ b/client/src/actions/access.js @@ -3,7 +3,6 @@ import { t } from 'i18next'; import apiClient from '../api/Api'; import { addErrorToast, addSuccessToast } from './index'; -import { getStats, getStatsConfig } from './stats'; import { normalizeTextarea } from '../helpers/helpers'; import { ACTION } from '../helpers/constants'; @@ -50,11 +49,13 @@ export const toggleClientBlockRequest = createAction('TOGGLE_CLIENT_BLOCK_REQUES export const toggleClientBlockFailure = createAction('TOGGLE_CLIENT_BLOCK_FAILURE'); export const toggleClientBlockSuccess = createAction('TOGGLE_CLIENT_BLOCK_SUCCESS'); -export const toggleClientBlock = (type, ip) => async (dispatch, getState) => { +export const toggleClientBlock = (type, ip) => async (dispatch) => { dispatch(toggleClientBlockRequest()); try { - const { allowed_clients, disallowed_clients, blocked_hosts } = getState().access; - let updatedDisallowedClients = normalizeTextarea(disallowed_clients); + const { + allowed_clients, disallowed_clients, blocked_hosts, + } = await apiClient.getAccessList(); + let updatedDisallowedClients = disallowed_clients; if (type === ACTION.unblock && updatedDisallowedClients.includes(ip)) { updatedDisallowedClients = updatedDisallowedClients.filter(client => client !== ip); @@ -63,23 +64,19 @@ export const toggleClientBlock = (type, ip) => async (dispatch, getState) => { } const values = { - allowed_clients: normalizeTextarea(allowed_clients), - blocked_hosts: normalizeTextarea(blocked_hosts), + allowed_clients, + blocked_hosts, disallowed_clients: updatedDisallowedClients, }; await apiClient.setAccessList(values); - dispatch(toggleClientBlockSuccess()); + dispatch(toggleClientBlockSuccess(values)); if (type === ACTION.unblock) { dispatch(addSuccessToast(t('client_unblocked', { ip }))); } else if (type === ACTION.block) { dispatch(addSuccessToast(t('client_blocked', { ip }))); } - - dispatch(getStats()); - dispatch(getStatsConfig()); - dispatch(getAccessList()); } catch (error) { dispatch(addErrorToast({ error })); dispatch(toggleClientBlockFailure()); diff --git a/client/src/actions/stats.js b/client/src/actions/stats.js index 7a12b203..25897aab 100644 --- a/client/src/actions/stats.js +++ b/client/src/actions/stats.js @@ -2,7 +2,7 @@ import { createAction } from 'redux-actions'; import apiClient from '../api/Api'; import { addErrorToast, addSuccessToast } from './index'; -import { normalizeTopStats, secondsToMilliseconds, getParamsForClientsSearch, addClientInfo, addClientStatus } from '../helpers/helpers'; +import { normalizeTopStats, secondsToMilliseconds, getParamsForClientsSearch, addClientInfo } from '../helpers/helpers'; export const getStatsConfigRequest = createAction('GET_STATS_CONFIG_REQUEST'); export const getStatsConfigFailure = createAction('GET_STATS_CONFIG_FAILURE'); @@ -46,15 +46,12 @@ export const getStats = () => async (dispatch) => { const normalizedTopClients = normalizeTopStats(stats.top_clients); const clientsParams = getParamsForClientsSearch(normalizedTopClients, 'name'); const clients = await apiClient.findClients(clientsParams); - const accessData = await apiClient.getAccessList(); - const { disallowed_clients } = accessData; const topClientsWithInfo = addClientInfo(normalizedTopClients, clients, 'name'); - const topClientsWithStatus = addClientStatus(topClientsWithInfo, disallowed_clients, 'name'); const normalizedStats = { ...stats, top_blocked_domains: normalizeTopStats(stats.top_blocked_domains), - top_clients: topClientsWithStatus, + top_clients: topClientsWithInfo, top_queried_domains: normalizeTopStats(stats.top_queried_domains), avg_processing_time: secondsToMilliseconds(stats.avg_processing_time), }; diff --git a/client/src/components/Dashboard/Clients.js b/client/src/components/Dashboard/Clients.js index 04c3270b..0a9ec903 100644 --- a/client/src/components/Dashboard/Clients.js +++ b/client/src/components/Dashboard/Clients.js @@ -57,10 +57,12 @@ const renderBlockingButton = (blocked, ip, handleClick, processing) => { ); }; -const clientCell = (t, toggleClientStatus, processing) => +const isBlockedClient = (clients, ip) => !!(clients && clients.includes(ip)); + +const clientCell = (t, toggleClientStatus, processing, disallowedClients) => function cell(row) { - const { original, value } = row; - const { blocked } = original; + const { value } = row; + const blocked = isBlockedClient(disallowedClients, value); return ( @@ -80,6 +82,7 @@ const Clients = ({ dnsQueries, toggleClientStatus, processingAccessSet, + disallowedClients, }) => ( parseInt(a.replace(/\./g, ''), 10) - parseInt(b.replace(/\./g, ''), 10), - Cell: clientCell(t, toggleClientStatus, processingAccessSet), + Cell: clientCell(t, toggleClientStatus, processingAccessSet, disallowedClients), }, { Header: requests_count, @@ -122,9 +125,9 @@ const Clients = ({ return {}; } - const { blocked } = rowInfo.original; + const { ip } = rowInfo.original; - if (blocked) { + if (isBlockedClient(disallowedClients, ip)) { return { className: 'red', }; @@ -148,6 +151,7 @@ Clients.propTypes = { t: PropTypes.func.isRequired, toggleClientStatus: PropTypes.func.isRequired, processingAccessSet: PropTypes.bool.isRequired, + disallowedClients: PropTypes.string.isRequired, }; export default withNamespaces()(Clients); diff --git a/client/src/components/Dashboard/index.js b/client/src/components/Dashboard/index.js index 01ce0448..d5db2388 100644 --- a/client/src/components/Dashboard/index.js +++ b/client/src/components/Dashboard/index.js @@ -19,6 +19,7 @@ class Dashboard extends Component { } getAllStats = () => { + this.props.getAccessList(); this.props.getStats(); this.props.getStatsConfig(); }; @@ -53,7 +54,8 @@ class Dashboard extends Component { dashboard, stats, access, t, } = this.props; const statsProcessing = stats.processingStats - || stats.processingGetConfig; + || stats.processingGetConfig + || access.processing; const subtitle = stats.interval === 1 @@ -130,6 +132,7 @@ class Dashboard extends Component { refreshButton={refreshButton} toggleClientStatus={this.toggleClientStatus} processingAccessSet={access.processingSet} + disallowedClients={access.disallowed_clients} />
diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index e748463e..977b0eae 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -122,17 +122,6 @@ export const addClientInfo = (data, clients, param) => ( }) ); -export const addClientStatus = (data, disallowedClients, param) => ( - data.map((row) => { - const clientIp = row[param]; - const blocked = !!(disallowedClients && disallowedClients.includes(clientIp)); - return { - ...row, - blocked, - }; - }) -); - export const normalizeFilteringStatus = (filteringStatus) => { const { enabled, filters, user_rules: userRules, interval, diff --git a/client/src/reducers/access.js b/client/src/reducers/access.js index 3ff517cf..79110279 100644 --- a/client/src/reducers/access.js +++ b/client/src/reducers/access.js @@ -34,7 +34,21 @@ const access = handleActions( [actions.toggleClientBlockRequest]: state => ({ ...state, processingSet: true }), [actions.toggleClientBlockFailure]: state => ({ ...state, processingSet: false }), - [actions.toggleClientBlockSuccess]: state => ({ ...state, processingSet: false }), + [actions.toggleClientBlockSuccess]: (state, { payload }) => { + const { + allowed_clients, + disallowed_clients, + blocked_hosts, + } = payload; + const newState = { + ...state, + allowed_clients: (allowed_clients && allowed_clients.join('\n')) || '', + disallowed_clients: (disallowed_clients && disallowed_clients.join('\n')) || '', + blocked_hosts: (blocked_hosts && blocked_hosts.join('\n')) || '', + processingSet: false, + }; + return newState; + }, }, { processing: true, From 6c18b71010cf28e1dfe147fd6400058f6e9224be Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Wed, 5 Feb 2020 14:30:43 +0300 Subject: [PATCH 08/10] *(dnsforward): fix safe search returning nxdomain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ Closes: https://github.com/AdguardTeam/AdGuardHome/issues/1387 --- dnsfilter/dnsfilter.go | 2 +- dnsfilter/security.go | 16 ++++++++-------- dnsforward/dnsforward.go | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/dnsfilter/dnsfilter.go b/dnsfilter/dnsfilter.go index 5ae9d523..ad73ec96 100644 --- a/dnsfilter/dnsfilter.go +++ b/dnsfilter/dnsfilter.go @@ -225,7 +225,7 @@ func (d *Dnsfilter) filtersInitializer() { // Close - close the object func (d *Dnsfilter) Close() { if d.rulesStorage != nil { - d.rulesStorage.Close() + _ = d.rulesStorage.Close() } } diff --git a/dnsfilter/security.go b/dnsfilter/security.go index c0341c99..7f2b397a 100644 --- a/dnsfilter/security.go +++ b/dnsfilter/security.go @@ -127,8 +127,8 @@ func (d *Dnsfilter) checkSafeSearch(host string) (Result, error) { res := Result{IsFiltered: true, Reason: FilteredSafeSearch} if ip := net.ParseIP(safeHost); ip != nil { res.IP = ip - len := d.setCacheResult(gctx.safeSearchCache, host, res) - log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, len) + valLen := d.setCacheResult(gctx.safeSearchCache, host, res) + log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, valLen) return res, nil } @@ -151,8 +151,8 @@ func (d *Dnsfilter) checkSafeSearch(host string) (Result, error) { } // Cache result - len := d.setCacheResult(gctx.safeSearchCache, host, res) - log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, len) + valLen := d.setCacheResult(gctx.safeSearchCache, host, res) + log.Debug("SafeSearch: stored in cache: %s (%d bytes)", host, valLen) return res, nil } @@ -243,8 +243,8 @@ func (d *Dnsfilter) checkSafeBrowsing(host string) (Result, error) { result.Rule = "adguard-malware-shavar" } - len := d.setCacheResult(gctx.safebrowsingCache, host, result) - log.Debug("SafeBrowsing: stored in cache: %s (%d bytes)", host, len) + valLen := d.setCacheResult(gctx.safebrowsingCache, host, result) + log.Debug("SafeBrowsing: stored in cache: %s (%d bytes)", host, valLen) return result, nil } @@ -283,8 +283,8 @@ func (d *Dnsfilter) checkParental(host string) (Result, error) { result.Rule = "parental CATEGORY_BLACKLISTED" } - len := d.setCacheResult(gctx.parentalCache, host, result) - log.Debug("Parental: stored in cache: %s (%d bytes)", host, len) + valLen := d.setCacheResult(gctx.parentalCache, host, result) + log.Debug("Parental: stored in cache: %s (%d bytes)", host, valLen) return result, err } diff --git a/dnsforward/dnsforward.go b/dnsforward/dnsforward.go index 1afdc262..7c001e27 100644 --- a/dnsforward/dnsforward.go +++ b/dnsforward/dnsforward.go @@ -883,7 +883,16 @@ func (s *Server) genDNSFilterMessage(d *proxy.DNSContext, result *dnsfilter.Resu case dnsfilter.FilteredParental: return s.genBlockedHost(m, s.conf.ParentalBlockHost, d) default: + // If the query was filtered by "Safe search", dnsfilter also must return + // the IP address that must be used in response. + // In this case regardless of the filtering method, we should return it + if result.Reason == dnsfilter.FilteredSafeSearch && result.IP != nil { + return s.genResponseWithIP(m, result.IP) + } + if s.conf.BlockingMode == "null_ip" { + // it means that we should return 0.0.0.0 or :: for any blocked request + switch m.Question[0].Qtype { case dns.TypeA: return s.genARecord(m, []byte{0, 0, 0, 0}) @@ -892,6 +901,8 @@ func (s *Server) genDNSFilterMessage(d *proxy.DNSContext, result *dnsfilter.Resu } } else if s.conf.BlockingMode == "custom_ip" { + // means that we should return custom IP for any blocked request + switch m.Question[0].Qtype { case dns.TypeA: return s.genARecord(m, s.conf.BlockingIPAddrv4) @@ -900,9 +911,14 @@ func (s *Server) genDNSFilterMessage(d *proxy.DNSContext, result *dnsfilter.Resu } } else if s.conf.BlockingMode == "nxdomain" { + // means that we should return NXDOMAIN for any blocked request + return s.genNXDomain(m) } + // Default blocking mode + // If there's an IP specified in the rule, return it + // If there is no IP, return NXDOMAIN if result.IP != nil { return s.genResponseWithIP(m, result.IP) } From fc88f59f6160c7d3520f22081cf569025b5fd5c8 Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Wed, 5 Feb 2020 17:38:23 +0300 Subject: [PATCH 09/10] *(global): fixed service implementation for OpenWrt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We now use a procd init script for OpenWrt just like it's recommended in the documentation. The service is automatically enabled on the install command. ✅ Closes: https://github.com/AdguardTeam/AdGuardHome/issues/1386 --- home/control_update.go | 9 -- home/helpers.go | 29 ++++- home/service.go | 237 ++++++++++++++++++++++++++--------------- 3 files changed, 180 insertions(+), 95 deletions(-) diff --git a/home/control_update.go b/home/control_update.go index 69c62885..6cabdcab 100644 --- a/home/control_update.go +++ b/home/control_update.go @@ -152,15 +152,6 @@ type updateInfo struct { newBinName string // Full path to the new executable file } -// Return TRUE if file exists -func fileExists(fn string) bool { - _, err := os.Stat(fn) - if err != nil { - return false - } - return true -} - // Fill in updateInfo object func getUpdateInfo(jsonData []byte) (*updateInfo, error) { var u updateInfo diff --git a/home/helpers.go b/home/helpers.go index ec95aa67..982a10ef 100644 --- a/home/helpers.go +++ b/home/helpers.go @@ -8,6 +8,7 @@ import ( "net/http" "net/url" "os" + "os/exec" "path" "path/filepath" "runtime" @@ -242,7 +243,7 @@ func checkPortAvailable(host string, port int) error { if err != nil { return err } - ln.Close() + _ = ln.Close() // It seems that net.Listener.Close() doesn't close file descriptors right away. // We wait for some time and hope that this fd will be closed. @@ -255,7 +256,7 @@ func checkPacketPortAvailable(host string, port int) error { if err != nil { return err } - ln.Close() + _ = ln.Close() // It seems that net.Listener.Close() doesn't close file descriptors right away. // We wait for some time and hope that this fd will be closed. @@ -329,6 +330,30 @@ func errorIsAddrInUse(err error) bool { return errErrno == syscall.EADDRINUSE } +// --------------------- +// general helpers +// --------------------- + +// fileExists returns TRUE if file exists +func fileExists(fn string) bool { + _, err := os.Stat(fn) + if err != nil { + return false + } + return true +} + +// runCommand runs shell command +func runCommand(command string, arguments ...string) (int, string, error) { + cmd := exec.Command(command, arguments...) + out, err := cmd.Output() + if err != nil { + return 1, "", fmt.Errorf("exec.Command(%s) failed: %s", command, err) + } + + return cmd.ProcessState.ExitCode(), string(out), nil +} + // --------------------- // debug logging helpers // --------------------- diff --git a/home/service.go b/home/service.go index 15baf30c..edca9244 100644 --- a/home/service.go +++ b/home/service.go @@ -1,10 +1,10 @@ package home import ( - "fmt" + "io/ioutil" "os" - "os/exec" "runtime" + "strings" "syscall" "github.com/AdguardTeam/golibs/log" @@ -41,23 +41,12 @@ func (p *program) Stop(s service.Service) error { return nil } -func runCommand(command string, arguments ...string) (int, string, error) { - cmd := exec.Command(command, arguments...) - out, err := cmd.Output() - if err != nil { - return 1, "", fmt.Errorf("exec.Command(%s) failed: %s", command, err) - } - - return cmd.ProcessState.ExitCode(), string(out), nil -} - // Check the service's status // Note: on OpenWrt 'service' utility may not exist - we use our service script directly in this case. func svcStatus(s service.Service) (service.Status, error) { status, err := s.Status() if err != nil && service.Platform() == "unix-systemv" { - confPath := "/etc/init.d/" + serviceName - code, _, err := runCommand("sh", "-c", confPath+" status") + code, err := runInitdCommand("status") if err != nil { return service.StatusStopped, nil } @@ -75,8 +64,7 @@ func svcAction(s service.Service, action string) error { err := service.Control(s, action) if err != nil && service.Platform() == "unix-systemv" && (action == "start" || action == "stop" || action == "restart") { - confPath := "/etc/init.d/" + serviceName - _, _, err := runCommand("sh", "-c", confPath+" "+action) + _, err := runInitdCommand(action) return err } return err @@ -114,61 +102,100 @@ func handleServiceControlAction(action string) { } if action == "status" { - status, errSt := svcStatus(s) - if errSt != nil { - log.Fatalf("failed to get service status: %s", errSt) - } - - switch status { - case service.StatusUnknown: - log.Printf("Service status is unknown") - case service.StatusStopped: - log.Printf("Service is stopped") - case service.StatusRunning: - log.Printf("Service is running") - } + handleServiceStatusCommand(s) } else if action == "run" { err = s.Run() if err != nil { log.Fatalf("Failed to run service: %s", err) } + } else if action == "install" { + handleServiceInstallCommand(s) + } else if action == "uninstall" { + handleServiceUninstallCommand(s) } else { - if action == "uninstall" { - // In case of Windows and Linux when a running service is being uninstalled, - // it is just marked for deletion but not stopped - // So we explicitly stop it here - _ = svcAction(s, "stop") - } - err = svcAction(s, action) if err != nil { log.Fatal(err) } - log.Printf("Action %s has been done successfully on %s", action, service.ChosenSystem().String()) + } - if action == "install" { - err := afterInstall() - if err != nil { - log.Fatal(err) - } + log.Printf("Action %s has been done successfully on %s", action, service.ChosenSystem().String()) +} - // Start automatically after install - err = svcAction(s, "start") - if err != nil { - log.Fatalf("Failed to start the service: %s", err) - } - log.Printf("Service has been started") +// handleServiceStatusCommand handles service "status" command +func handleServiceStatusCommand(s service.Service) { + status, errSt := svcStatus(s) + if errSt != nil { + log.Fatalf("failed to get service status: %s", errSt) + } - if detectFirstRun() { - log.Printf(`Almost ready! + switch status { + case service.StatusUnknown: + log.Printf("Service status is unknown") + case service.StatusStopped: + log.Printf("Service is stopped") + case service.StatusRunning: + log.Printf("Service is running") + } +} + +// handleServiceStatusCommand handles service "install" command +func handleServiceInstallCommand(s service.Service) { + err := svcAction(s, "install") + if err != nil { + log.Fatal(err) + } + + if isOpenWrt() { + // On OpenWrt it is important to run enable after the service installation + // Otherwise, the service won't start on the system startup + _, err := runInitdCommand("enable") + if err != nil { + log.Fatal(err) + } + } + + // Start automatically after install + err = svcAction(s, "start") + if err != nil { + log.Fatalf("Failed to start the service: %s", err) + } + log.Printf("Service has been started") + + if detectFirstRun() { + log.Printf(`Almost ready! AdGuard Home is successfully installed and will automatically start on boot. There are a few more things that must be configured before you can use it. Click on the link below and follow the Installation Wizard steps to finish setup.`) - printHTTPAddresses("http") - } + printHTTPAddresses("http") + } +} - } else if action == "uninstall" { - cleanupService() +// handleServiceStatusCommand handles service "uninstall" command +func handleServiceUninstallCommand(s service.Service) { + if isOpenWrt() { + // On OpenWrt it is important to run disable command first + // as it will remove the symlink + _, err := runInitdCommand("disable") + if err != nil { + log.Fatal(err) + } + } + + err := svcAction(s, "uninstall") + if err != nil { + log.Fatal(err) + } + + if runtime.GOOS == "darwin" { + // Removing log files on cleanup and ignore errors + err := os.Remove(launchdStdoutPath) + if err != nil && !os.IsNotExist(err) { + log.Printf("cannot remove %s", launchdStdoutPath) + } + err = os.Remove(launchdStderrPath) + if err != nil && !os.IsNotExist(err) { + log.Printf("cannot remove %s", launchdStderrPath) } } } @@ -191,43 +218,33 @@ func configureService(c *service.Config) { // Use modified service file templates c.Option["SystemdScript"] = systemdScript c.Option["SysvScript"] = sysvScript + + // On OpenWrt we're using a different type of sysvScript + if isOpenWrt() { + c.Option["SysvScript"] = openWrtScript + } } -// On SysV systems supported by kardianos/service package, there must be multiple /etc/rc{N}.d directories. -// On OpenWrt, however, there is only /etc/rc.d - we handle this case ourselves. -// We also use relative path, because this is how all other service files are set up. -func afterInstall() error { - if service.Platform() == "unix-systemv" && fileExists("/etc/rc.d") { - confPath := "../init.d/" + serviceName - err := os.Symlink(confPath, "/etc/rc.d/S99"+serviceName) - if err != nil { - return err - } - } - return nil +// runInitdCommand runs init.d service command +// returns command code or error if any +func runInitdCommand(action string) (int, error) { + confPath := "/etc/init.d/" + serviceName + code, _, err := runCommand("sh", "-c", confPath+" "+action) + return code, err } -// cleanupService called on the service uninstall, cleans up additional files if needed -func cleanupService() { - if runtime.GOOS == "darwin" { - // Removing log files on cleanup and ignore errors - err := os.Remove(launchdStdoutPath) - if err != nil && !os.IsNotExist(err) { - log.Printf("cannot remove %s", launchdStdoutPath) - } - err = os.Remove(launchdStderrPath) - if err != nil && !os.IsNotExist(err) { - log.Printf("cannot remove %s", launchdStderrPath) - } +// isOpenWrt checks if OS is OpenWRT +func isOpenWrt() bool { + if runtime.GOOS != "linux" { + return false } - if service.Platform() == "unix-systemv" { - fn := "/etc/rc.d/S99" + serviceName - err := os.Remove(fn) - if err != nil && !os.IsNotExist(err) { - log.Printf("os.Remove: %s: %s", fn, err) - } + body, err := ioutil.ReadFile("/etc/os-release") + if err != nil { + return false } + + return strings.Contains(string(body), "OpenWrt") } // Basically the same template as the one defined in github.com/kardianos/service @@ -388,3 +405,55 @@ case "$1" in esac exit 0 ` + +// OpenWrt procd init script +// https://github.com/AdguardTeam/AdGuardHome/issues/1386 +const openWrtScript = `#!/bin/sh /etc/rc.common + +USE_PROCD=1 + +START=95 +STOP=01 + +cmd="{{.Path}}{{range .Arguments}} {{.|cmd}}{{end}}" +name="{{.Name}}" +pid_file="/var/run/${name}.pid" + +start_service() { + echo "Starting ${name}" + + procd_open_instance + procd_set_param command ${cmd} + procd_set_param respawn # respawn automatically if something died + procd_set_param stdout 1 # forward stdout of the command to logd + procd_set_param stderr 1 # same for stderr + procd_set_param pidfile ${pid_file} # write a pid file on instance start and remove it on stop + + procd_close_instance + echo "${name} has been started" +} + +stop_service() { + echo "Stopping ${name}" +} + +EXTRA_COMMANDS="status" +EXTRA_HELP=" status Print the service status" + +get_pid() { + cat "${pid_file}" +} + +is_running() { + [ -f "${pid_file}" ] && ps | grep -v grep | grep $(get_pid) >/dev/null 2>&1 +} + +status() { + if is_running; then + echo "Running" + else + echo "Stopped" + exit 1 + fi +} +` From 808618602c092956a9c0ae7ca1b300ca8be98d55 Mon Sep 17 00:00:00 2001 From: Andrey Meshkov Date: Thu, 6 Feb 2020 20:55:37 +0300 Subject: [PATCH 10/10] *(global): fix ARM build auto-update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ Closes: https://github.com/AdguardTeam/AdGuardHome/issues/1391 --- Makefile | 3 +-- home/control_update.go | 4 +++- home/home.go | 6 +++++- main.go | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 0c3bd56b..74934562 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,6 @@ GOPATH := $(shell go env GOPATH) JSFILES = $(shell find client -path client/node_modules -prune -o -type f -name '*.js') STATIC = build/static/index.html CHANNEL ?= release -GOARM_VER := TARGET=AdGuardHome @@ -24,7 +23,7 @@ $(STATIC): $(JSFILES) client/node_modules $(TARGET): $(STATIC) *.go home/*.go dhcpd/*.go dnsfilter/*.go dnsforward/*.go GOOS=$(NATIVE_GOOS) GOARCH=$(NATIVE_GOARCH) GO111MODULE=off go get -v github.com/gobuffalo/packr/... PATH=$(GOPATH)/bin:$(PATH) packr -z - CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=$(GIT_VERSION) -X main.channel=$(CHANNEL) -X main.goarm=$(GOARM_VER)" -asmflags="-trimpath=$(PWD)" -gcflags="-trimpath=$(PWD)" + CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=$(GIT_VERSION) -X main.channel=$(CHANNEL) -X main.goarm=$(GOARM)" -asmflags="-trimpath=$(PWD)" -gcflags="-trimpath=$(PWD)" PATH=$(GOPATH)/bin:$(PATH) packr clean clean: diff --git a/home/control_update.go b/home/control_update.go index 6cabdcab..7864cfbb 100644 --- a/home/control_update.go +++ b/home/control_update.go @@ -42,8 +42,10 @@ func getVersionResp(data []byte) []byte { return []byte{} } + // the key is download_linux_arm or download_linux_arm64 for regular ARM versions dloadName := fmt.Sprintf("download_%s_%s", runtime.GOOS, runtime.GOARCH) - if runtime.GOARCH == "arm" && ARMVersion != "6" { + if runtime.GOARCH == "arm" && ARMVersion == "5" { + // the key is download_linux_armv5 for ARMv5 dloadName = fmt.Sprintf("download_%s_%sv%s", runtime.GOOS, runtime.GOARCH, ARMVersion) } _, ok := versionJSON[dloadName] diff --git a/home/home.go b/home/home.go index b965b74c..5b34847b 100644 --- a/home/home.go +++ b/home/home.go @@ -101,7 +101,11 @@ func run(args options) { configureLogger(args) // print the first message after logger is configured - log.Printf("AdGuard Home, version %s, channel %s\n", versionString, updateChannel) + msg := "AdGuard Home, version %s, channel %s\n, arch %s %s" + if ARMVersion != "" { + msg = msg + " v" + ARMVersion + } + log.Printf(msg, versionString, updateChannel, runtime.GOOS, runtime.GOARCH, ARMVersion) log.Debug("Current working directory is %s", config.ourWorkingDir) if args.runningAsService { log.Info("AdGuard Home is running as a service") diff --git a/main.go b/main.go index 9d441aee..36946082 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,7 @@ var version = "undefined" // channel can be set via ldflags var channel = "release" -// ARM version number. Set via linker flags. +// GOARM value - set via ldflags var goarm = "" func main() {