From 421ad744cb36f20167f723dee9966439d2bd14c5 Mon Sep 17 00:00:00 2001
From: ArtemBaskal <a.baskal@adguard.com>
Date: Mon, 6 Apr 2020 20:07:32 +0300
Subject: [PATCH 1/5] + client: Validate adding of absolute path to the
 filtering lists

---
 client/src/__locales/en.json           |  3 ++-
 client/src/components/Filters/Form.js  |  6 +++---
 client/src/components/Filters/Table.js | 20 ++++++++++----------
 client/src/helpers/constants.js        |  2 ++
 client/src/helpers/form.js             | 15 ++++++++++++++-
 5 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json
index 02929a8e..461e0a19 100644
--- a/client/src/__locales/en.json
+++ b/client/src/__locales/en.json
@@ -140,7 +140,7 @@
     "add_allowlist": "Add allowlist",
     "cancel_btn": "Cancel",
     "enter_name_hint": "Enter name",
-    "enter_url_hint": "Enter URL",
+    "enter_url_or_path_hint": "Enter URL or absolute path of the list",
     "check_updates_btn": "Check for updates",
     "new_blocklist": "New blocklist",
     "new_allowlist": "New allowlist",
@@ -149,6 +149,7 @@
     "enter_valid_blocklist": "Enter a valid URL to the blocklist.",
     "enter_valid_allowlist": "Enter a valid URL to the allowlist.",
     "form_error_url_format": "Invalid url format",
+    "form_error_url_or_path_format": "Invalid url or absolute path of the list",
     "custom_filter_rules": "Custom filtering rules",
     "custom_filter_rules_hint": "Enter one rule on a line. You can use either adblock rules or hosts files syntax.",
     "examples_title": "Examples",
diff --git a/client/src/components/Filters/Form.js b/client/src/components/Filters/Form.js
index 22993a1f..4056802a 100644
--- a/client/src/components/Filters/Form.js
+++ b/client/src/components/Filters/Form.js
@@ -4,7 +4,7 @@ import { Field, reduxForm } from 'redux-form';
 import { Trans, withNamespaces } from 'react-i18next';
 import flow from 'lodash/flow';
 
-import { renderInputField, required, isValidUrl } from '../../helpers/form';
+import { renderInputField, required, isValidPath } from '../../helpers/form';
 
 const Form = (props) => {
     const {
@@ -37,8 +37,8 @@ const Form = (props) => {
                         type="text"
                         component={renderInputField}
                         className="form-control"
-                        placeholder={t('enter_url_hint')}
-                        validate={[required, isValidUrl]}
+                        placeholder={t('enter_url_or_path_hint')}
+                        validate={[required, isValidPath]}
                     />
                 </div>
                 <div className="form__description">
diff --git a/client/src/components/Filters/Table.js b/client/src/components/Filters/Table.js
index 4df02e92..5d866150 100644
--- a/client/src/components/Filters/Table.js
+++ b/client/src/components/Filters/Table.js
@@ -2,11 +2,10 @@ import React, { Component } from 'react';
 import PropTypes from 'prop-types';
 import ReactTable from 'react-table';
 import { withNamespaces, Trans } from 'react-i18next';
-
 import CellWrap from '../ui/CellWrap';
-
 import { MODAL_TYPE } from '../../helpers/constants';
 import { formatDetailedDateTime } from '../../helpers/helpers';
+import { isValidAbsolutePath } from '../../helpers/form';
 
 class Table extends Component {
     getDateCell = row => CellWrap(row, formatDetailedDateTime);
@@ -50,14 +49,15 @@ class Table extends Component {
             minWidth: 200,
             Cell: ({ value }) => (
                 <div className="logs__row logs__row--overflow">
-                    <a
-                        href={value}
-                        target="_blank"
-                        rel="noopener noreferrer"
-                        className="link logs__text"
-                    >
-                        {value}
-                    </a>
+                    {isValidAbsolutePath(value) ? value :
+                        <a
+                            href={value}
+                            target="_blank"
+                            rel="noopener noreferrer"
+                            className="link logs__text"
+                        >
+                            {value}
+                        </a>}
                 </div>
             ),
         },
diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js
index ae214526..69faa01b 100644
--- a/client/src/helpers/constants.js
+++ b/client/src/helpers/constants.js
@@ -6,6 +6,8 @@ export const R_CIDR = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(
 export const R_MAC = /^((([a-fA-F0-9][a-fA-F0-9]+[-]){5}|([a-fA-F0-9][a-fA-F0-9]+[:]){5})([a-fA-F0-9][a-fA-F0-9])$)|(^([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]+[.]){2}([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]))$/;
 export const R_CIDR_IPV6 = /^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))$/;
 export const R_PATH_LAST_PART = /\/[^/]*$/;
+export const R_UNIX_ABSOLUTE_PATH = /^\/([A-z0-9-_+]+\/)*([A-z0-9]+\.(txt))$/;
+export const R_WIN_ABSOLUTE_PATH = /^[a-zA-Z]:\\[\\\S|*\S]?.*\.(txt)$/;
 
 export const STATS_NAMES = {
     avg_processing_time: 'average_processing_time',
diff --git a/client/src/helpers/form.js b/client/src/helpers/form.js
index 840b3f83..d075feee 100644
--- a/client/src/helpers/form.js
+++ b/client/src/helpers/form.js
@@ -1,7 +1,10 @@
 import React, { Fragment } from 'react';
 import { Trans } from 'react-i18next';
 import PropTypes from 'prop-types';
-import { R_IPV4, R_MAC, R_HOST, R_IPV6, R_CIDR, R_CIDR_IPV6, UNSAFE_PORTS, R_URL_REQUIRES_PROTOCOL } from '../helpers/constants';
+import {
+    R_IPV4, R_MAC, R_HOST, R_IPV6, R_CIDR, R_CIDR_IPV6,
+    UNSAFE_PORTS, R_URL_REQUIRES_PROTOCOL, R_WIN_ABSOLUTE_PATH, R_UNIX_ABSOLUTE_PATH,
+} from '../helpers/constants';
 import { createOnBlurHandler } from './helpers';
 
 export const renderField = (props, elementType) => {
@@ -289,4 +292,14 @@ export const isValidUrl = (value) => {
     return undefined;
 };
 
+export const isValidAbsolutePath = value => R_WIN_ABSOLUTE_PATH.test(value)
+    || R_UNIX_ABSOLUTE_PATH.test(value);
+
+export const isValidPath = (value) => {
+    if (value && !isValidAbsolutePath(value) && !R_URL_REQUIRES_PROTOCOL.test(value)) {
+        return <Trans>form_error_url_or_path_format</Trans>;
+    }
+    return undefined;
+};
+
 export const toNumber = value => value && parseInt(value, 10);

From 683121ef909a8b721f6c3ed1d56b2a9b44f8cfba Mon Sep 17 00:00:00 2001
From: ArtemBaskal <a.baskal@adguard.com>
Date: Tue, 7 Apr 2020 11:39:21 +0300
Subject: [PATCH 2/5] Fix file path regexps to match files without extension

---
 client/src/helpers/constants.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js
index 69faa01b..e0526696 100644
--- a/client/src/helpers/constants.js
+++ b/client/src/helpers/constants.js
@@ -6,8 +6,8 @@ export const R_CIDR = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(
 export const R_MAC = /^((([a-fA-F0-9][a-fA-F0-9]+[-]){5}|([a-fA-F0-9][a-fA-F0-9]+[:]){5})([a-fA-F0-9][a-fA-F0-9])$)|(^([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]+[.]){2}([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]))$/;
 export const R_CIDR_IPV6 = /^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))$/;
 export const R_PATH_LAST_PART = /\/[^/]*$/;
-export const R_UNIX_ABSOLUTE_PATH = /^\/([A-z0-9-_+]+\/)*([A-z0-9]+\.(txt))$/;
-export const R_WIN_ABSOLUTE_PATH = /^[a-zA-Z]:\\[\\\S|*\S]?.*\.(txt)$/;
+export const R_UNIX_ABSOLUTE_PATH = /^\/([A-z0-9-_+]+\/)*([A-z0-9]+(\.[A-z0-9]+)?)$/;
+export const R_WIN_ABSOLUTE_PATH = /^[a-zA-Z]:\\[\\\S|*\S]?.*$/;
 
 export const STATS_NAMES = {
     avg_processing_time: 'average_processing_time',

From b8d868efe4f4bc4e47a9db9a2492fd00f17e2276 Mon Sep 17 00:00:00 2001
From: ArtemBaskal <a.baskal@adguard.com>
Date: Tue, 7 Apr 2020 12:19:14 +0300
Subject: [PATCH 3/5] Fix translations

---
 client/src/__locales/en.json | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json
index 461e0a19..2004987f 100644
--- a/client/src/__locales/en.json
+++ b/client/src/__locales/en.json
@@ -140,7 +140,7 @@
     "add_allowlist": "Add allowlist",
     "cancel_btn": "Cancel",
     "enter_name_hint": "Enter name",
-    "enter_url_or_path_hint": "Enter URL or absolute path of the list",
+    "enter_url_or_path_hint": "Enter a URL or an absolute path of the list",
     "check_updates_btn": "Check for updates",
     "new_blocklist": "New blocklist",
     "new_allowlist": "New allowlist",
@@ -148,8 +148,8 @@
     "edit_allowlist": "Edit allowlist",
     "enter_valid_blocklist": "Enter a valid URL to the blocklist.",
     "enter_valid_allowlist": "Enter a valid URL to the allowlist.",
-    "form_error_url_format": "Invalid url format",
-    "form_error_url_or_path_format": "Invalid url or absolute path of the list",
+    "form_error_url_format": "Invalid URL format",
+    "form_error_url_or_path_format": "Invalid URL or absolute path of the list",
     "custom_filter_rules": "Custom filtering rules",
     "custom_filter_rules_hint": "Enter one rule on a line. You can use either adblock rules or hosts files syntax.",
     "examples_title": "Examples",

From 92376690a4d7a1aeb3c65488685dcec6fdc6b4d6 Mon Sep 17 00:00:00 2001
From: ArtemBaskal <a.baskal@adguard.com>
Date: Tue, 7 Apr 2020 19:52:36 +0300
Subject: [PATCH 4/5] Change win absolute path regex

---
 client/src/helpers/constants.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js
index e0526696..85dedd52 100644
--- a/client/src/helpers/constants.js
+++ b/client/src/helpers/constants.js
@@ -7,7 +7,7 @@ export const R_MAC = /^((([a-fA-F0-9][a-fA-F0-9]+[-]){5}|([a-fA-F0-9][a-fA-F0-9]
 export const R_CIDR_IPV6 = /^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))$/;
 export const R_PATH_LAST_PART = /\/[^/]*$/;
 export const R_UNIX_ABSOLUTE_PATH = /^\/([A-z0-9-_+]+\/)*([A-z0-9]+(\.[A-z0-9]+)?)$/;
-export const R_WIN_ABSOLUTE_PATH = /^[a-zA-Z]:\\[\\\S|*\S]?.*$/;
+export const R_WIN_ABSOLUTE_PATH = /^([a-zA-Z]:)?(\\|\/)(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$/;
 
 export const STATS_NAMES = {
     avg_processing_time: 'average_processing_time',

From af2adc5b33c4263733159e25fa4ff9581440f703 Mon Sep 17 00:00:00 2001
From: ArtemBaskal <a.baskal@adguard.com>
Date: Wed, 8 Apr 2020 14:21:20 +0300
Subject: [PATCH 5/5] Change absolute path regexps

---
 client/src/helpers/constants.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js
index 85dedd52..d0e933df 100644
--- a/client/src/helpers/constants.js
+++ b/client/src/helpers/constants.js
@@ -6,8 +6,10 @@ export const R_CIDR = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(
 export const R_MAC = /^((([a-fA-F0-9][a-fA-F0-9]+[-]){5}|([a-fA-F0-9][a-fA-F0-9]+[:]){5})([a-fA-F0-9][a-fA-F0-9])$)|(^([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]+[.]){2}([a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]))$/;
 export const R_CIDR_IPV6 = /^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))$/;
 export const R_PATH_LAST_PART = /\/[^/]*$/;
-export const R_UNIX_ABSOLUTE_PATH = /^\/([A-z0-9-_+]+\/)*([A-z0-9]+(\.[A-z0-9]+)?)$/;
-export const R_WIN_ABSOLUTE_PATH = /^([a-zA-Z]:)?(\\|\/)(?:[^\\/:*?"<>|\r\n]+\\)*[^\\/:*?"<>|\r\n]*$/;
+// eslint-disable-next-line no-control-regex
+export const R_UNIX_ABSOLUTE_PATH = /^(\/[^/\x00]+)+$/;
+// eslint-disable-next-line no-control-regex
+export const R_WIN_ABSOLUTE_PATH = /^([a-zA-Z]:)?(\\|\/)(?:[^\\/:*?"<>|\x00]+\\)*[^\\/:*?"<>|\x00]*$/;
 
 export const STATS_NAMES = {
     avg_processing_time: 'average_processing_time',