Full rework of the query log

Squashed commit of the following:

commit e8a72eb223551f17e637136713dae03accf8ab9e
Author: Andrey Meshkov <am@adguard.com>
Date:   Thu Jun 18 00:31:53 2020 +0300

    fix race in whois test

commit 801d28197f888fa21f83c9a0b49e3c9472c08513
Merge: 9d9787fd b1c951fb
Author: Andrey Meshkov <am@adguard.com>
Date:   Thu Jun 18 00:28:13 2020 +0300

    Merge branch 'master' into feature/1421

commit 9d9787fd79b17f76c7baed52c12ac462fd00a5e4
Merge: 4ce337ca 08e238ab
Author: Andrey Meshkov <am@adguard.com>
Date:   Thu Jun 18 00:27:32 2020 +0300

    Merge

commit 4ce337ca7aec163edf87a038bb25fb44e64f8613
Author: Andrey Meshkov <am@adguard.com>
Date:   Thu Jun 18 00:22:49 2020 +0300

    -(home): fix whois test

commit 08e238ab0e723b1e354f58245e9a8d5017b392c9
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Thu Jun 18 00:13:41 2020 +0300

    Add comments

commit 5f108065952bcc25dce1c2eee3f9401d2641a6e9
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Jun 17 23:47:50 2020 +0300

    Make tooltip position absolute for touch

commit 4c30a583165e5d007d4b01b657de8751a7bd8c7b
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Jun 17 20:39:44 2020 +0300

    Prevent scroll hide for touch devices

commit 62da97931f5921613762614717c62c77ddb6b8db
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Jun 17 20:06:24 2020 +0300

    Review changes: ipad tooltip

commit 12dddcca8caca51c157b5d25dfa3ca03ba7f0c06
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Jun 17 16:59:16 2020 +0300

    Add close tooltip event for ipad

commit 62191e41d5bf67317f9f1dc6c6af08cbabb4bf90
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Jun 17 16:39:40 2020 +0300

    Add success toast on logs refresh

commit 2ebdd6a8124269d737c8060c3247aaf35d85cb8b
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Jun 17 16:01:37 2020 +0300

    Fix pagination

commit 5820c92bacd93d05a3d66d42ee95f099e1c5d9e9
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Jun 17 11:31:15 2020 +0300

    Revert "Render table in chunks"

    This reverts commit cdfcd849ccddc1bc35591edac7904129431470c9.

commit cdfcd849ccddc1bc35591edac7904129431470c9
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Jun 16 18:42:18 2020 +0300

    Render table in chunks

commit cc8c5e64274bf6e806e2e8a4bf305af745c3ed2a
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Jun 16 17:35:24 2020 +0300

    Add pagination button hover effect

commit f7e134091a1556784a5fea9d83c50353536126ef
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Jun 16 16:28:00 2020 +0300

    Make loader position absolute

commit a7b887b57d903f1f7ac967b861b5cc677728efc4
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Jun 16 15:42:20 2020 +0300

    Ignore clients find without params

commit ecb322fefd4a161d79f28d17fe27827ee91701e4
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Jun 16 15:30:48 2020 +0300

    Styles changes

commit 9323ce3938bf04e1290eade09201ba0790a250c0
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Jun 16 14:32:23 2020 +0300

    Review styles changes

commit e0faa04ba3643f01b2ca99524cdd52b0731725c7
Merge: 98576823 15e71435
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Jun 16 12:08:45 2020 +0300

    Merge branch '1421-new-qlog-v2' into feature/1421

commit 9857682371e8d9a3a91933cfb58a26b3470675d9
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Mon Jun 15 18:32:02 2020 +0300

    Fix response cell

... and 88 more commits
This commit is contained in:
Artem Baskal
2020-06-18 00:36:19 +03:00
parent b1c951fb2c
commit e39fe1b913
81 changed files with 3415 additions and 1087 deletions

View File

@@ -55,7 +55,8 @@ export const EMPTY_DATE = '0001-01-01T00:00:00Z';
export const DEBOUNCE_TIMEOUT = 300;
export const DEBOUNCE_FILTER_TIMEOUT = 500;
export const CHECK_TIMEOUT = 1000;
export const STOP_TIMEOUT = 10000;
export const SUCCESS_TOAST_TIMEOUT = 5000;
export const FAILURE_TOAST_TIMEOUT = 30000;
export const UNSAFE_PORTS = [
1,
@@ -256,18 +257,6 @@ export const ENCRYPTION_SOURCE = {
CONTENT: 'content',
};
export const FILTERED_STATUS = {
FILTERED_BLACK_LIST: 'FilteredBlackList',
NOT_FILTERED_WHITE_LIST: 'NotFilteredWhiteList',
NOT_FILTERED_NOT_FOUND: 'NotFilteredNotFound',
FILTERED_BLOCKED_SERVICE: 'FilteredBlockedService',
REWRITE: 'Rewrite',
REWRITE_HOSTS: 'RewriteEtcHosts',
FILTERED_SAFE_SEARCH: 'FilteredSafeSearch',
FILTERED_SAFE_BROWSING: 'FilteredSafeBrowsing',
FILTERED_PARENTAL: 'FilteredParental',
};
export const FILTERED = 'Filtered';
export const NOT_FILTERED = 'NotFiltered';
@@ -336,25 +325,124 @@ export const DNS_RECORD_TYPES = [
];
export const DEFAULT_LOGS_FILTER = {
filter_domain: '',
filter_client: '',
filter_question_type: '',
filter_response_status: '',
search: '',
response_status: '',
};
export const DEFAULT_LANGUAGE = 'en';
export const TABLE_DEFAULT_PAGE_SIZE = 100;
export const TABLE_DEFAULT_PAGE_SIZE = 50;
export const SMALL_TABLE_DEFAULT_PAGE_SIZE = 20;
export const TABLE_FIRST_PAGE = 0;
export const LEASES_TABLE_DEFAULT_PAGE_SIZE = 20;
export const FILTERED_STATUS = {
FILTERED_BLACK_LIST: 'FilteredBlackList',
NOT_FILTERED_WHITE_LIST: 'NotFilteredWhiteList',
NOT_FILTERED_NOT_FOUND: 'NotFilteredNotFound',
FILTERED_BLOCKED_SERVICE: 'FilteredBlockedService',
REWRITE: 'Rewrite',
REWRITE_HOSTS: 'RewriteEtcHosts',
FILTERED_SAFE_SEARCH: 'FilteredSafeSearch',
FILTERED_SAFE_BROWSING: 'FilteredSafeBrowsing',
FILTERED_PARENTAL: 'FilteredParental',
};
export const RESPONSE_FILTER = {
ALL: 'all',
FILTERED: 'filtered',
ALL: {
query: 'all',
label: 'show_all_responses',
},
FILTERED: {
query: 'filtered',
label: 'filtered',
},
PROCESSED: {
query: 'processed',
label: 'show_processed_responses',
},
SPACE: {
query: 'all',
label: '',
disabled: true,
},
BLOCKED: {
query: 'blocked',
label: 'show_blocked_responses',
},
BLOCKED_THREATS: {
query: 'blocked_safebrowsing',
label: 'blocked_threats',
},
BLOCKED_ADULT_WEBSITES: {
query: 'blocked_parental',
label: 'blocked_adult_websites',
},
ALLOWED: {
query: 'whitelisted',
label: 'allowed',
},
REWRITTEN: {
query: 'rewritten',
label: 'rewritten',
},
SAFE_SEARCH: {
query: 'safe_search',
label: 'safe_search',
},
};
export const FILTERED_STATUS_TO_META_MAP = {
[FILTERED_STATUS.NOT_FILTERED_WHITE_LIST]: {
label: RESPONSE_FILTER.ALLOWED.label,
color: 'green',
},
[FILTERED_STATUS.NOT_FILTERED_NOT_FOUND]: {
label: RESPONSE_FILTER.PROCESSED.label,
color: 'white',
},
[FILTERED_STATUS.FILTERED_BLOCKED_SERVICE]: {
label: RESPONSE_FILTER.BLOCKED.label,
color: 'red',
},
[FILTERED_STATUS.FILTERED_SAFE_SEARCH]: {
label: RESPONSE_FILTER.SAFE_SEARCH.label,
color: 'yellow',
},
[FILTERED_STATUS.FILTERED_BLACK_LIST]: {
label: RESPONSE_FILTER.BLOCKED.label,
color: 'red',
},
[FILTERED_STATUS.REWRITE]: {
label: RESPONSE_FILTER.REWRITTEN.label,
color: 'blue',
},
[FILTERED_STATUS.REWRITE_HOSTS]: {
label: RESPONSE_FILTER.REWRITTEN.label,
color: 'blue',
},
[FILTERED_STATUS.FILTERED_SAFE_BROWSING]: {
label: RESPONSE_FILTER.BLOCKED_THREATS.label,
color: 'yellow',
},
[FILTERED_STATUS.FILTERED_PARENTAL]: {
label: RESPONSE_FILTER.BLOCKED_ADULT_WEBSITES.label,
color: 'yellow',
},
};
export const DEFAULT_TIME_FORMAT = 'HH:mm:ss';
export const LONG_TIME_FORMAT = 'HH:mm:ss.SSS';
export const DEFAULT_SHORT_DATE_FORMAT_OPTIONS = {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour12: false,
};
export const DEFAULT_DATE_FORMAT_OPTIONS = {
year: 'numeric',
month: 'numeric',
@@ -371,9 +459,15 @@ export const DETAILED_DATE_FORMAT_OPTIONS = {
export const CUSTOM_FILTERING_RULES_ID = 0;
export const ACTION = {
block: 'block',
unblock: 'unblock',
export const BLOCK_ACTIONS = {
BLOCK: 'block',
UNBLOCK: 'unblock',
};
export const SCHEME_TO_PROTOCOL_MAP = {
doh: 'dns_over_https',
dot: 'dns_over_tls',
'': 'plain_dns',
};
export const DNS_REQUEST_OPTIONS = {
@@ -407,3 +501,7 @@ export const FORM_NAME = {
INSTALL: 'install',
LOGIN: 'login',
};
export const smallScreenSize = 767;
export const touchMediaQuery = '(hover: none)';

View File

@@ -85,10 +85,10 @@ export const renderGroupField = ({
&& <span className="input-group-append">
<button
type="button"
className="btn btn-secondary btn-icon"
className="btn btn-secondary btn-icon btn-icon--green"
onClick={removeField}
>
<svg className="icon icon--close">
<svg className="icon icon--small">
<use xlinkHref="#cross" />
</svg>
</button>

View File

@@ -5,37 +5,40 @@ import { WHOIS_ICONS } from './constants';
const getFormattedWhois = (whois, t) => {
const whoisInfo = normalizeWhois(whois);
return (
Object.keys(whoisInfo).map((key) => {
const icon = WHOIS_ICONS[key];
return (
<span className="logs__whois text-muted" key={key} title={t(key)}>
Object.keys(whoisInfo)
.map((key) => {
const icon = WHOIS_ICONS[key];
return (
<span className="logs__whois text-muted" key={key} title={t(key)}>
{icon && (
<Fragment>
<svg className="logs__whois-icon icons">
<use xlinkHref={`#${icon}`} />
</svg>&nbsp;
</svg>
&nbsp;
</Fragment>
)}{whoisInfo[key]}
</span>
);
})
);
})
);
};
export const formatClientCell = (row, t) => {
const { value, original: { info } } = row;
export const formatClientCell = (row, t, isDetailed = false) => {
const { info, client } = row.original;
let whoisContainer = '';
let nameContainer = value;
let nameContainer = client;
if (info) {
const { name, whois_info } = info;
if (name) {
nameContainer = (
<span className="logs__text logs__text--wrap" title={`${name} (${value})`}>
{name} <small>({value})</small>
</span>
);
nameContainer = isDetailed ? <small title={client}>{client}</small>
: <div className="logs__text logs__text--nowrap"
title={`${name} (${client})`}>
{name}
<small>{`(${client})`}</small>
</div>;
}
if (whois_info) {
@@ -48,11 +51,11 @@ export const formatClientCell = (row, t) => {
}
return (
<span className="logs__text">
<Fragment>
<div className="logs__text" title={client}>
<>
{nameContainer}
{whoisContainer}
</Fragment>
</span>
</>
</div>
);
};

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-bitwise */
import 'url-polyfill';
import dateParse from 'date-fns/parse';
import dateFormat from 'date-fns/format';
@@ -13,29 +12,30 @@ import i18n from 'i18next';
import uniqBy from 'lodash/uniqBy';
import ipaddr from 'ipaddr.js';
import versionCompare from './versionCompare';
import { getTrackerData } from './trackers/trackers';
import {
STANDARD_DNS_PORT,
STANDARD_WEB_PORT,
STANDARD_HTTPS_PORT,
CHECK_TIMEOUT,
DNS_RECORD_TYPES,
DEFAULT_TIME_FORMAT,
DEFAULT_DATE_FORMAT_OPTIONS,
DETAILED_DATE_FORMAT_OPTIONS,
DEFAULT_LANGUAGE,
FILTERED_STATUS,
DEFAULT_TIME_FORMAT,
DETAILED_DATE_FORMAT_OPTIONS,
DNS_RECORD_TYPES,
FILTERED,
FILTERED_STATUS,
IP_MATCH_LIST_STATUS,
STANDARD_DNS_PORT,
STANDARD_HTTPS_PORT,
STANDARD_WEB_PORT,
} from './constants';
/**
* @param time {string} The time to format
* @returns {string} Returns the time in the format HH:mm:ss
*/
export const formatTime = (time) => {
export const formatTime = (time, options = DEFAULT_TIME_FORMAT) => {
const parsedTime = dateParse(time);
return dateFormat(parsedTime, DEFAULT_TIME_FORMAT);
return dateFormat(parsedTime, options);
};
/**
@@ -68,34 +68,48 @@ export const isToday = (date) => isSameDay(new Date(date), new Date());
export const normalizeLogs = (logs) => logs.map((log) => {
const {
time,
question,
answer: response,
reason,
answer,
answer_dnssec,
client,
client_proto,
elapsedMs,
question,
reason,
status,
time,
filterId,
rule,
service_name,
status,
original_answer,
upstream,
} = log;
const { host: domain, type } = question;
const responsesArray = response ? response.map((response) => {
const response = answer ? answer.map((response) => {
const { value, type, ttl } = response;
return `${type}: ${value} (ttl=${ttl})`;
}) : [];
const tracker = getTrackerData(domain);
return {
time,
domain,
type,
response: responsesArray,
response,
reason,
client,
client_proto,
filterId,
rule,
status,
serviceName: service_name,
originalAnswer: original_answer,
tracker,
answer_dnssec,
elapsedMs,
upstream,
};
});
@@ -562,3 +576,15 @@ export const getIpMatchListStatus = (ip, list) => {
return IP_MATCH_LIST_STATUS.NOT_FOUND;
}
};
/**
* @param {string} elapsedMs
* @param {function} t translate
* @returns {string}
*/
export const formatElapsedMs = (elapsedMs, t) => {
const formattedElapsedMs = parseInt(elapsedMs, 10) || parseFloat(elapsedMs)
.toFixed(2);
return `${formattedElapsedMs} ${t('milliseconds_abbreviation')}`;
};

View File

@@ -3,13 +3,13 @@ import adguardDb from './adguard.json';
import { REPOSITORY } from '../constants';
/**
@typedef TrackerData
@type {object}
@property {string} id - tracker ID.
@property {string} name - tracker name.
@property {string} url - tracker website url.
@property {number} category - tracker category.
@property {source} source - tracker data source.
@typedef TrackerData
@type {object}
@property {string} id - tracker ID.
@property {string} name - tracker name.
@property {string} url - tracker website url.
@property {number} category - tracker category.
@property {source} source - tracker data source.
*/
/**
@@ -20,45 +20,6 @@ export const sources = {
ADGUARD: 2,
};
/**
* Gets tracker data in the specified database
*
* @param {String} domainName domain name to check
* @param {*} trackersDb trackers database
* @param {number} source source ID
* @returns {TrackerData} tracker data or null if no matching tracker found
*/
const getTrackerDataFromDb = (domainName, trackersDb, source) => {
if (!domainName) {
return null;
}
const parts = domainName.split(/\./g).reverse();
let hostToCheck = '';
// Check every subdomain
for (let i = 0; i < parts.length; i += 1) {
hostToCheck = parts[i] + (i > 0 ? '.' : '') + hostToCheck;
const trackerId = trackersDb.trackerDomains[hostToCheck];
if (trackerId) {
const trackerData = trackersDb.trackers[trackerId];
const categoryName = trackersDb.categories[trackerData.categoryId];
return {
id: trackerId,
name: trackerData.name,
url: trackerData.url,
category: categoryName,
source,
};
}
}
// No tracker found for the specified domain
return null;
};
/**
* Gets the source metadata for the specified tracker
* @param {TrackerData} trackerData tracker data
@@ -74,7 +35,8 @@ export const getSourceData = (trackerData) => {
name: 'Whotracks.me',
url: `https://whotracks.me/trackers/${trackerData.id}.html`,
};
} if (trackerData.source === sources.ADGUARD) {
}
if (trackerData.source === sources.ADGUARD) {
return {
name: 'AdGuard',
url: REPOSITORY.TRACKERS_DB,
@@ -84,6 +46,49 @@ export const getSourceData = (trackerData) => {
return null;
};
/**
* Gets tracker data in the specified database
*
* @param {String} domainName domain name to check
* @param {*} trackersDb trackers database
* @param {number} source source ID
* @returns {TrackerData} tracker data or null if no matching tracker found
*/
const getTrackerDataFromDb = (domainName, trackersDb, source) => {
if (!domainName) {
return null;
}
const parts = domainName.split(/\./g)
.reverse();
let hostToCheck = '';
// Check every subdomain
for (let i = 0; i < parts.length; i += 1) {
hostToCheck = parts[i] + (i > 0 ? '.' : '') + hostToCheck;
const trackerId = trackersDb.trackerDomains[hostToCheck];
if (trackerId) {
const trackerData = trackersDb.trackers[trackerId];
const categoryName = trackersDb.categories[trackerData.categoryId];
trackerData.source = source;
const sourceData = getSourceData(trackerData);
return {
id: trackerId,
name: trackerData.name,
url: trackerData.url,
category: categoryName,
source,
sourceData,
};
}
}
// No tracker found for the specified domain
return null;
};
/**
* Gets tracker data from the trackers database
*