- client: Match client IP strictly: Merge pull request #620 in DNS/adguard-home from fix/1687 to master
Close #1687
Squashed commit of the following:
commit 5287da0b98d154d4243abdb4b9021006499c225f
Merge: c6b50c70 83b9b701
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Fri May 29 12:47:23 2020 +0300
Merge branch 'master' into fix/1687
commit c6b50c70a5089fcadfd2606b07b3b84769db2760
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Fri May 29 12:42:12 2020 +0300
minor
commit dab9fa9ee0502838b4e10aef93d037c2fb5bf41b
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Thu May 28 16:56:08 2020 +0300
Add support for exact matching of long and short ipv6 notations, add tests
commit e72e86cda81af2c5e54f93abb2890438fd3648b0
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Thu May 28 13:57:22 2020 +0300
Update helper, write tests
commit 92f4c34224ab7927b02edde829f2d9653a00a854
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Wed May 27 18:35:05 2020 +0300
Make variable names more expressive
commit 3d38f21281237e9cccbba26afc1ab641947c5dc0
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Wed May 27 17:09:08 2020 +0300
Add ipv6 cidr support
commit 7db0a2fb18ccd96d8d1def73f12138e4f4e37f71
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Tue May 26 12:48:57 2020 +0300
Minor
commit 65e87f3899aab3417cac57bab0a8fa371cafd4ec
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Tue May 26 12:46:30 2020 +0300
Add breaks between helpers
commit 3f38bdfe7bc17e019bf048c79c9e8f1336b6f3d3
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Thu May 21 20:17:27 2020 +0300
- client: Match client IP strictly
This commit is contained in:
parent
83b9b70166
commit
72f253f62b
|
@ -1,16 +0,0 @@
|
||||||
{
|
|
||||||
"presets": [
|
|
||||||
[
|
|
||||||
"@babel/preset-env",
|
|
||||||
{
|
|
||||||
"modules": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@babel/preset-react"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
"@babel/plugin-proposal-class-properties",
|
|
||||||
"@babel/plugin-transform-runtime",
|
|
||||||
"@babel/plugin-proposal-object-rest-spread"
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
module.exports = (api) => {
|
||||||
|
api.cache(false);
|
||||||
|
return {
|
||||||
|
presets: [
|
||||||
|
'@babel/preset-env',
|
||||||
|
'@babel/preset-react',
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
'@babel/plugin-proposal-class-properties',
|
||||||
|
'@babel/plugin-transform-runtime',
|
||||||
|
'@babel/plugin-proposal-object-rest-spread',
|
||||||
|
],
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
transform: {
|
||||||
|
'^.+\\.jsx?$': 'babel-jest',
|
||||||
|
},
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
|
@ -6,7 +6,9 @@
|
||||||
"build-dev": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js",
|
"build-dev": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js",
|
||||||
"watch": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js --watch",
|
"watch": "cross-env BUILD_ENV=dev webpack --config webpack.dev.js --watch",
|
||||||
"build-prod": "cross-env BUILD_ENV=prod webpack --config webpack.prod.js",
|
"build-prod": "cross-env BUILD_ENV=prod webpack --config webpack.prod.js",
|
||||||
"lint": "eslint src"
|
"lint": "eslint src",
|
||||||
|
"test": "jest",
|
||||||
|
"test:watch": "jest --watch"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nivo/line": "^0.49.1",
|
"@nivo/line": "^0.49.1",
|
||||||
|
@ -15,6 +17,7 @@
|
||||||
"date-fns": "^1.29.0",
|
"date-fns": "^1.29.0",
|
||||||
"i18next": "^19.4.4",
|
"i18next": "^19.4.4",
|
||||||
"i18next-browser-languagedetector": "^4.2.0",
|
"i18next-browser-languagedetector": "^4.2.0",
|
||||||
|
"ipaddr.js": "^1.9.1",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"nanoid": "^3.1.9",
|
"nanoid": "^3.1.9",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
@ -60,6 +63,7 @@
|
||||||
"eslint-plugin-react-hooks": "^2.5.0",
|
"eslint-plugin-react-hooks": "^2.5.0",
|
||||||
"file-loader": "6.0.0",
|
"file-loader": "6.0.0",
|
||||||
"html-webpack-plugin": "^4.3.0",
|
"html-webpack-plugin": "^4.3.0",
|
||||||
|
"jest": "^26.0.1",
|
||||||
"mini-css-extract-plugin": "^0.9.0",
|
"mini-css-extract-plugin": "^0.9.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"postcss-flexbugs-fixes": "4.2.1",
|
"postcss-flexbugs-fixes": "4.2.1",
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import App from '../components/App';
|
|
||||||
|
|
||||||
it('renders without crashing', () => {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
ReactDOM.render(<App />, div);
|
|
||||||
ReactDOM.unmountComponentAtNode(div);
|
|
||||||
});
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
import { getIpMatchListStatus } from '../helpers/helpers';
|
||||||
|
import { IP_MATCH_LIST_STATUS } from '../helpers/constants';
|
||||||
|
|
||||||
|
describe('getIpMatchListStatus', () => {
|
||||||
|
describe('IPv4', () => {
|
||||||
|
test('should return EXACT on find the exact ip match', () => {
|
||||||
|
const list = `127.0.0.2
|
||||||
|
2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
192.168.0.1/8
|
||||||
|
127.0.0.1
|
||||||
|
127.0.0.3`;
|
||||||
|
expect(getIpMatchListStatus('127.0.0.1', list))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.EXACT);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return CIDR on find the cidr match', () => {
|
||||||
|
const list = `127.0.0.2
|
||||||
|
2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
192.168.0.1/8
|
||||||
|
127.0.0.0/24
|
||||||
|
127.0.0.3`;
|
||||||
|
expect(getIpMatchListStatus('127.0.0.1', list))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.CIDR);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return NOT_FOUND if the ip is not in the list', () => {
|
||||||
|
const list = `127.0.0.1
|
||||||
|
2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
192.168.0.1/8
|
||||||
|
127.0.0.2
|
||||||
|
127.0.0.3`;
|
||||||
|
expect(getIpMatchListStatus('127.0.0.4', list))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.NOT_FOUND);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return the first EXACT or CIDR match in the list', () => {
|
||||||
|
const list1 = `2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
127.0.0.1
|
||||||
|
127.0.0.8/24
|
||||||
|
127.0.0.3`;
|
||||||
|
expect(getIpMatchListStatus('127.0.0.1', list1))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.EXACT);
|
||||||
|
|
||||||
|
const list2 = `2001:db8:11a3:9d7:ffff:ffff:ffff:ffff
|
||||||
|
2001:0db8:11a3:09d7:0000:0000:0000:0000/64
|
||||||
|
127.0.0.0/24
|
||||||
|
127.0.0.1
|
||||||
|
127.0.0.8/24
|
||||||
|
127.0.0.3`;
|
||||||
|
expect(getIpMatchListStatus('127.0.0.1', list2))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.CIDR);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('IPv6', () => {
|
||||||
|
test('should return EXACT on find the exact ip match', () => {
|
||||||
|
const list = `127.0.0.0
|
||||||
|
2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
2001:db8:11a3:9d7:ffff:ffff:ffff:ffff
|
||||||
|
127.0.0.1`;
|
||||||
|
expect(getIpMatchListStatus('2001:db8:11a3:9d7:0:0:0:0', list))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.EXACT);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return EXACT on find the exact ip match of short and long notation', () => {
|
||||||
|
const list = `127.0.0.0
|
||||||
|
192.168.0.1/8
|
||||||
|
2001:db8::
|
||||||
|
127.0.0.2`;
|
||||||
|
expect(getIpMatchListStatus('2001:db8:0:0:0:0:0:0', list))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.EXACT);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return CIDR on find the cidr match', () => {
|
||||||
|
const list1 = `2001:0db8:11a3:09d7:0000:0000:0000:0000/64
|
||||||
|
127.0.0.1
|
||||||
|
127.0.0.2`;
|
||||||
|
expect(getIpMatchListStatus('2001:db8:11a3:9d7:0:0:0:0', list1))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.CIDR);
|
||||||
|
|
||||||
|
const list2 = `2001:0db8::/16
|
||||||
|
127.0.0.0
|
||||||
|
2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
2001:db8::
|
||||||
|
2001:db8:11a3:9d7:ffff:ffff:ffff:ffff
|
||||||
|
127.0.0.1`;
|
||||||
|
expect(getIpMatchListStatus('2001:db1::', list2))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.CIDR);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return NOT_FOUND if the ip is not in the list', () => {
|
||||||
|
const list = `2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
2001:0db8:11a3:09d7:0000:0000:0000:0000/64
|
||||||
|
127.0.0.1
|
||||||
|
127.0.0.2`;
|
||||||
|
expect(getIpMatchListStatus('::', list))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.NOT_FOUND);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return the first EXACT or CIDR match in the list', () => {
|
||||||
|
const list1 = `2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
2001:0db8:11a3:09d7:0000:0000:0000:0000/64
|
||||||
|
127.0.0.3`;
|
||||||
|
expect(getIpMatchListStatus('2001:db8:11a3:9d7:0:0:0:0', list1))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.EXACT);
|
||||||
|
|
||||||
|
const list2 = `2001:0db8:11a3:09d7:0000:0000:0000:0000/64
|
||||||
|
2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
127.0.0.3`;
|
||||||
|
expect(getIpMatchListStatus('2001:db8:11a3:9d7:0:0:0:0', list2))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.CIDR);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Empty list or IP', () => {
|
||||||
|
test('should return NOT_FOUND on empty ip', () => {
|
||||||
|
const list = `127.0.0.0
|
||||||
|
2001:db8:11a3:9d7:0:0:0:0
|
||||||
|
2001:db8:11a3:9d7:ffff:ffff:ffff:ffff
|
||||||
|
127.0.0.1`;
|
||||||
|
expect(getIpMatchListStatus('', list))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.NOT_FOUND);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return NOT_FOUND on empty list', () => {
|
||||||
|
const list = '';
|
||||||
|
expect(getIpMatchListStatus('127.0.0.1', list))
|
||||||
|
.toEqual(IP_MATCH_LIST_STATUS.NOT_FOUND);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,14 +6,15 @@ import { Trans, withTranslation } from 'react-i18next';
|
||||||
import Card from '../ui/Card';
|
import Card from '../ui/Card';
|
||||||
import Cell from '../ui/Cell';
|
import Cell from '../ui/Cell';
|
||||||
|
|
||||||
import { getPercent } from '../../helpers/helpers';
|
import { getPercent, getIpMatchListStatus } from '../../helpers/helpers';
|
||||||
import { STATUS_COLORS } from '../../helpers/constants';
|
import { IP_MATCH_LIST_STATUS, STATUS_COLORS } from '../../helpers/constants';
|
||||||
import { formatClientCell } from '../../helpers/formatClientCell';
|
import { formatClientCell } from '../../helpers/formatClientCell';
|
||||||
|
|
||||||
const getClientsPercentColor = (percent) => {
|
const getClientsPercentColor = (percent) => {
|
||||||
if (percent > 50) {
|
if (percent > 50) {
|
||||||
return STATUS_COLORS.green;
|
return STATUS_COLORS.green;
|
||||||
} if (percent > 10) {
|
}
|
||||||
|
if (percent > 10) {
|
||||||
return STATUS_COLORS.yellow;
|
return STATUS_COLORS.yellow;
|
||||||
}
|
}
|
||||||
return STATUS_COLORS.red;
|
return STATUS_COLORS.red;
|
||||||
|
@ -27,20 +28,18 @@ const countCell = (dnsQueries) => function cell(row) {
|
||||||
return <Cell value={value} percent={percent} color={percentColor} />;
|
return <Cell value={value} percent={percent} color={percentColor} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderBlockingButton = (blocked, ip, handleClick, processing) => {
|
const renderBlockingButton = (ipMatchListStatus, ip, handleClick, processing) => {
|
||||||
let buttonProps = {
|
const buttonProps = ipMatchListStatus === IP_MATCH_LIST_STATUS.NOT_FOUND
|
||||||
|
? {
|
||||||
className: 'btn-outline-danger',
|
className: 'btn-outline-danger',
|
||||||
text: 'block_btn',
|
text: 'block_btn',
|
||||||
type: 'block',
|
type: 'block',
|
||||||
};
|
}
|
||||||
|
: {
|
||||||
if (blocked) {
|
|
||||||
buttonProps = {
|
|
||||||
className: 'btn-outline-secondary',
|
className: 'btn-outline-secondary',
|
||||||
text: 'unblock_btn',
|
text: 'unblock_btn',
|
||||||
type: 'unblock',
|
type: 'unblock',
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="table__action">
|
<div className="table__action">
|
||||||
|
@ -56,18 +55,17 @@ const renderBlockingButton = (blocked, ip, handleClick, processing) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isBlockedClient = (clients, ip) => !!(clients && clients.includes(ip));
|
|
||||||
|
|
||||||
const clientCell = (t, toggleClientStatus, processing, disallowedClients) => function cell(row) {
|
const clientCell = (t, toggleClientStatus, processing, disallowedClients) => function cell(row) {
|
||||||
const { value } = row;
|
const { value } = row;
|
||||||
const blocked = isBlockedClient(disallowedClients, value);
|
const ipMatchListStatus = getIpMatchListStatus(value, disallowedClients);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div className="logs__row logs__row--overflow logs__row--column">
|
<div className="logs__row logs__row--overflow logs__row--column">
|
||||||
{formatClientCell(row, t)}
|
{formatClientCell(row, t)}
|
||||||
</div>
|
</div>
|
||||||
{renderBlockingButton(blocked, value, toggleClientStatus, processing)}
|
{ipMatchListStatus !== IP_MATCH_LIST_STATUS.CIDR
|
||||||
|
&& renderBlockingButton(ipMatchListStatus, value, toggleClientStatus, processing)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -124,15 +122,8 @@ const Clients = ({
|
||||||
|
|
||||||
const { ip } = rowInfo.original;
|
const { ip } = rowInfo.original;
|
||||||
|
|
||||||
if (isBlockedClient(disallowedClients, ip)) {
|
return getIpMatchListStatus(ip, disallowedClients)
|
||||||
return {
|
=== IP_MATCH_LIST_STATUS.NOT_FOUND ? {} : { className: 'red' };
|
||||||
className: 'red',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
className: '',
|
|
||||||
};
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { Field, reduxForm } from 'redux-form';
|
||||||
import { Trans, withTranslation } from 'react-i18next';
|
import { Trans, withTranslation } from 'react-i18next';
|
||||||
import flow from 'lodash/flow';
|
import flow from 'lodash/flow';
|
||||||
import { renderTextareaField } from '../../../../helpers/form';
|
import { renderTextareaField } from '../../../../helpers/form';
|
||||||
|
import { normalizeMultiline } from '../../../../helpers/helpers';
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
{
|
{
|
||||||
|
@ -44,6 +45,7 @@ const Form = (props) => {
|
||||||
type="text"
|
type="text"
|
||||||
className="form-control form-control--textarea font-monospace"
|
className="form-control form-control--textarea font-monospace"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
normalizeOnBlur={normalizeMultiline}
|
||||||
/>
|
/>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
||||||
|
|
|
@ -379,3 +379,9 @@ export const DNS_REQUEST_OPTIONS = {
|
||||||
PARALLEL_REQUESTS: 'parallel_requests',
|
PARALLEL_REQUESTS: 'parallel_requests',
|
||||||
FASTEST_ADDR: 'fastest_addr',
|
FASTEST_ADDR: 'fastest_addr',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const IP_MATCH_LIST_STATUS = {
|
||||||
|
NOT_FOUND: 'NOT_FOUND', // not found in the list
|
||||||
|
EXACT: 'EXACT', // found exact match (ip === ip)
|
||||||
|
CIDR: 'CIDR', // the ip is in the specified CIDR range
|
||||||
|
};
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable no-bitwise */
|
||||||
import 'url-polyfill';
|
import 'url-polyfill';
|
||||||
import dateParse from 'date-fns/parse';
|
import dateParse from 'date-fns/parse';
|
||||||
import dateFormat from 'date-fns/format';
|
import dateFormat from 'date-fns/format';
|
||||||
|
@ -10,6 +11,7 @@ import round from 'lodash/round';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import i18n from 'i18next';
|
import i18n from 'i18next';
|
||||||
import uniqBy from 'lodash/uniqBy';
|
import uniqBy from 'lodash/uniqBy';
|
||||||
|
import ipaddr from 'ipaddr.js';
|
||||||
import versionCompare from './versionCompare';
|
import versionCompare from './versionCompare';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -24,6 +26,7 @@ import {
|
||||||
DEFAULT_LANGUAGE,
|
DEFAULT_LANGUAGE,
|
||||||
FILTERED_STATUS,
|
FILTERED_STATUS,
|
||||||
FILTERED,
|
FILTERED,
|
||||||
|
IP_MATCH_LIST_STATUS,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,7 +170,10 @@ export const getPercent = (amount, number) => {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const captitalizeWords = (text) => text.split(/[ -_]/g).map((str) => str.charAt(0).toUpperCase() + str.substr(1)).join(' ');
|
export const captitalizeWords = (text) => text.split(/[ -_]/g)
|
||||||
|
.map((str) => str.charAt(0)
|
||||||
|
.toUpperCase() + str.substr(1))
|
||||||
|
.join(' ');
|
||||||
|
|
||||||
export const getInterfaceIp = (option) => {
|
export const getInterfaceIp = (option) => {
|
||||||
const onlyIPv6 = option.ip_addresses.every((ip) => ip.includes(':'));
|
const onlyIPv6 = option.ip_addresses.every((ip) => ip.includes(':'));
|
||||||
|
@ -187,7 +193,8 @@ export const getInterfaceIp = (option) => {
|
||||||
export const getIpList = (interfaces) => {
|
export const getIpList = (interfaces) => {
|
||||||
let list = [];
|
let list = [];
|
||||||
|
|
||||||
Object.keys(interfaces).forEach((item) => {
|
Object.keys(interfaces)
|
||||||
|
.forEach((item) => {
|
||||||
list = [...list, ...interfaces[item].ip_addresses];
|
list = [...list, ...interfaces[item].ip_addresses];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -283,7 +290,9 @@ export const normalizeTextarea = (text) => {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return text.replace(/[;, ]/g, '\n').split('\n').filter((n) => n);
|
return text.replace(/[;, ]/g, '\n')
|
||||||
|
.split('\n')
|
||||||
|
.filter((n) => n);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -307,7 +316,10 @@ export const normalizeTopClients = (topClients) => topClients.reduce(
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
nameToCountMap.configured[infoName] = count;
|
nameToCountMap.configured[infoName] = count;
|
||||||
return nameToCountMap;
|
return nameToCountMap;
|
||||||
}, { auto: {}, configured: {} },
|
}, {
|
||||||
|
auto: {},
|
||||||
|
configured: {},
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getClientInfo = (clients, ip) => {
|
export const getClientInfo = (clients, ip) => {
|
||||||
|
@ -321,7 +333,10 @@ export const getClientInfo = (clients, ip) => {
|
||||||
const { name, whois_info } = client;
|
const { name, whois_info } = client;
|
||||||
const whois = Object.keys(whois_info).length > 0 ? whois_info : '';
|
const whois = Object.keys(whois_info).length > 0 ? whois_info : '';
|
||||||
|
|
||||||
return { name, whois };
|
return {
|
||||||
|
name,
|
||||||
|
whois,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAutoClientInfo = (clients, ip) => {
|
export const getAutoClientInfo = (clients, ip) => {
|
||||||
|
@ -334,7 +349,10 @@ export const getAutoClientInfo = (clients, ip) => {
|
||||||
const { name, whois_info } = client;
|
const { name, whois_info } = client;
|
||||||
const whois = Object.keys(whois_info).length > 0 ? whois_info : '';
|
const whois = Object.keys(whois_info).length > 0 ? whois_info : '';
|
||||||
|
|
||||||
return { name, whois };
|
return {
|
||||||
|
name,
|
||||||
|
whois,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const sortClients = (clients) => {
|
export const sortClients = (clients) => {
|
||||||
|
@ -344,7 +362,8 @@ export const sortClients = (clients) => {
|
||||||
|
|
||||||
if (nameA > nameB) {
|
if (nameA > nameB) {
|
||||||
return 1;
|
return 1;
|
||||||
} if (nameA < nameB) {
|
}
|
||||||
|
if (nameA < nameB) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,7 +385,8 @@ export const secondsToMilliseconds = (seconds) => {
|
||||||
return seconds;
|
return seconds;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const normalizeRulesTextarea = (text) => text && text.replace(/^\n/g, '').replace(/\n\s*\n/g, '\n');
|
export const normalizeRulesTextarea = (text) => text && text.replace(/^\n/g, '')
|
||||||
|
.replace(/\n\s*\n/g, '\n');
|
||||||
|
|
||||||
export const isVersionGreater = (currentVersion, previousVersion) => (
|
export const isVersionGreater = (currentVersion, previousVersion) => (
|
||||||
versionCompare(currentVersion, previousVersion) === -1
|
versionCompare(currentVersion, previousVersion) === -1
|
||||||
|
@ -449,10 +469,17 @@ export const getCurrentFilter = (url, filters) => {
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
const { enabled, name, url } = filter;
|
const { enabled, name, url } = filter;
|
||||||
return { enabled, name, url };
|
return {
|
||||||
|
enabled,
|
||||||
|
name,
|
||||||
|
url,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { name: '', url: '' };
|
return {
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -463,3 +490,59 @@ export const formatNumber = (num) => {
|
||||||
const currentLanguage = i18n.languages[0] || DEFAULT_LANGUAGE;
|
const currentLanguage = i18n.languages[0] || DEFAULT_LANGUAGE;
|
||||||
return num.toLocaleString(currentLanguage);
|
return num.toLocaleString(currentLanguage);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const normalizeMultiline = (multiline) => `${normalizeTextarea(multiline)
|
||||||
|
.map((line) => line.trim())
|
||||||
|
.join('\n')}\n`;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param parsedIp {object} ipaddr.js IPv4 or IPv6 object
|
||||||
|
* @param cidr {array} ipaddr.js CIDR array
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export const isIpMatchCidr = (parsedIp, parsedCidr) => {
|
||||||
|
try {
|
||||||
|
const cidrIpVersion = parsedCidr[0].kind();
|
||||||
|
const ipVersion = parsedIp.kind();
|
||||||
|
|
||||||
|
return ipVersion === cidrIpVersion && parsedIp.match(parsedCidr);
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ip {string}
|
||||||
|
* @param list {string}
|
||||||
|
* @returns {'EXACT' | 'CIDR' | 'NOT_FOND'}
|
||||||
|
*/
|
||||||
|
export const getIpMatchListStatus = (ip, list) => {
|
||||||
|
if (!ip || !list) {
|
||||||
|
return IP_MATCH_LIST_STATUS.NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
const listArr = list.trim()
|
||||||
|
.split('\n');
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < listArr.length; i += 1) {
|
||||||
|
const listItem = listArr[i];
|
||||||
|
|
||||||
|
const parsedIp = ipaddr.parse(ip);
|
||||||
|
const isItemAnIp = ipaddr.isValid(listItem);
|
||||||
|
const parsedItem = isItemAnIp ? ipaddr.parse(listItem) : ipaddr.parseCIDR(listItem);
|
||||||
|
|
||||||
|
if (isItemAnIp && parsedIp.toString() === parsedItem.toString()) {
|
||||||
|
return IP_MATCH_LIST_STATUS.EXACT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isItemAnIp && isIpMatchCidr(parsedIp, parsedItem)) {
|
||||||
|
return IP_MATCH_LIST_STATUS.CIDR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return IP_MATCH_LIST_STATUS.NOT_FOUND;
|
||||||
|
} catch (e) {
|
||||||
|
return IP_MATCH_LIST_STATUS.NOT_FOUND;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue