Compare commits
16 Commits
v0.107.0-b
...
v0.107.0-b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb4cd312c2 | ||
|
|
1265be507a | ||
|
|
e064e0f277 | ||
|
|
595441603f | ||
|
|
d1de47b636 | ||
|
|
e5c73877c8 | ||
|
|
77821ec816 | ||
|
|
9f52adf33d | ||
|
|
8454e65cd9 | ||
|
|
756c70644d | ||
|
|
16092e8ba9 | ||
|
|
b92db25e6a | ||
|
|
b81030ba70 | ||
|
|
9809ed8019 | ||
|
|
9246c1340e | ||
|
|
550b1798a1 |
1
.github/stale.yml
vendored
1
.github/stale.yml
vendored
@@ -5,6 +5,7 @@
|
||||
# Issues with these labels will never be considered stale.
|
||||
'exemptLabels':
|
||||
- 'bug'
|
||||
- 'documentation'
|
||||
- 'enhancement'
|
||||
- 'feature request'
|
||||
- 'localization'
|
||||
|
||||
56
CHANGELOG.md
56
CHANGELOG.md
@@ -10,11 +10,13 @@ and this project adheres to
|
||||
## [Unreleased]
|
||||
|
||||
<!--
|
||||
## [v0.107.0] - 2021-08-03 (APPROX.)
|
||||
## [v0.107.0] - 2021-09-14 (APPROX.)
|
||||
-->
|
||||
|
||||
### Added
|
||||
|
||||
- New `FastestTimeout` field that replaces the default timeout for dialing the
|
||||
IP addresses when AdGuard Home works in "Fastest IP address" mode ([#1992]).
|
||||
- Static IP address detection on FreeBSD ([#3289]).
|
||||
- Optimistic cache ([#2145]).
|
||||
- New possible value of `6h` for `querylog_interval` setting ([#2504]).
|
||||
@@ -27,7 +29,8 @@ and this project adheres to
|
||||
- Settable timeouts for querying the upstream servers ([#2280]).
|
||||
- Configuration file parameters to change group and user ID on startup on Unix
|
||||
([#2763]).
|
||||
- Experimental OpenBSD support for AMD64 and 64-bit ARM CPUs ([#2439], [#3225]).
|
||||
- Experimental OpenBSD support for AMD64 and 64-bit ARM CPUs ([#2439], [#3225],
|
||||
[#3226]).
|
||||
- Support for custom port in DNS-over-HTTPS profiles for Apple's devices
|
||||
([#3172]).
|
||||
- `darwin/arm64` support ([#2443]).
|
||||
@@ -43,6 +46,8 @@ and this project adheres to
|
||||
|
||||
### Changed
|
||||
|
||||
- Don't show the private key in API responses if it was saved as a string
|
||||
([#1898]).
|
||||
- Better OpenWrt detection ([#3435]).
|
||||
- DNS-over-HTTPS queries that come from HTTP proxies in the `trusted_proxies`
|
||||
list now use the real IP address of the client instead of the address of the
|
||||
@@ -59,12 +64,54 @@ and this project adheres to
|
||||
file, together with the new `group` and `user` settings ([#2763]).
|
||||
- Permissions on filter files are now `0o644` instead of `0o600` ([#3198]).
|
||||
|
||||
#### Configuration Changes
|
||||
|
||||
In this release, the schema version has changed from 10 to 12.
|
||||
|
||||
- Parameter `dns.querylog_interval`, which in schema versions 11 and earlier
|
||||
used to be an integer number of days, is now a string with a human-readable
|
||||
duration:
|
||||
|
||||
```yaml
|
||||
# BEFORE:
|
||||
'dns':
|
||||
# …
|
||||
'querylog_interval': 90
|
||||
|
||||
# AFTER:
|
||||
'dns':
|
||||
# …
|
||||
'querylog_interval': '2160h'
|
||||
```
|
||||
|
||||
To rollback this change, convert the parameter back into days and change the
|
||||
`schema_version` back to `11`.
|
||||
|
||||
- Parameter `rlimit_nofile`, which in schema versions 10 and earlier used to be
|
||||
on the top level, is now moved to the new `os` object:
|
||||
|
||||
```yaml
|
||||
# BEFORE:
|
||||
'rlimit_nofile': 42
|
||||
|
||||
# AFTER:
|
||||
'os':
|
||||
'group': ''
|
||||
'rlimit_nofile': 42
|
||||
'user': ''
|
||||
```
|
||||
|
||||
To rollback this change, move the parameter on the top level and change the
|
||||
`schema_version` back to `10`.
|
||||
|
||||
### Deprecated
|
||||
|
||||
- Go 1.16 support. v0.108.0 will require at least Go 1.17 to build.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Occasional panics when reading old statistics databases ([#3506]).
|
||||
- `reload` service action on macOS and FreeBSD ([#3457]).
|
||||
- Inaccurate using of service actions in the installation script ([#3450]).
|
||||
- Client ID checking ([#3437]).
|
||||
- Discovering other DHCP servers on `darwin` and `freebsd` ([#3417]).
|
||||
@@ -93,6 +140,8 @@ and this project adheres to
|
||||
|
||||
[#1381]: https://github.com/AdguardTeam/AdGuardHome/issues/1381
|
||||
[#1691]: https://github.com/AdguardTeam/AdGuardHome/issues/1691
|
||||
[#1898]: https://github.com/AdguardTeam/AdGuardHome/issues/1898
|
||||
[#1992]: https://github.com/AdguardTeam/AdGuardHome/issues/1992
|
||||
[#2141]: https://github.com/AdguardTeam/AdGuardHome/issues/2141
|
||||
[#2145]: https://github.com/AdguardTeam/AdGuardHome/issues/2145
|
||||
[#2280]: https://github.com/AdguardTeam/AdGuardHome/issues/2280
|
||||
@@ -117,6 +166,7 @@ and this project adheres to
|
||||
[#3198]: https://github.com/AdguardTeam/AdGuardHome/issues/3198
|
||||
[#3217]: https://github.com/AdguardTeam/AdGuardHome/issues/3217
|
||||
[#3225]: https://github.com/AdguardTeam/AdGuardHome/issues/3225
|
||||
[#3226]: https://github.com/AdguardTeam/AdGuardHome/issues/3226
|
||||
[#3256]: https://github.com/AdguardTeam/AdGuardHome/issues/3256
|
||||
[#3257]: https://github.com/AdguardTeam/AdGuardHome/issues/3257
|
||||
[#3289]: https://github.com/AdguardTeam/AdGuardHome/issues/3289
|
||||
@@ -128,6 +178,8 @@ and this project adheres to
|
||||
[#3435]: https://github.com/AdguardTeam/AdGuardHome/issues/3435
|
||||
[#3437]: https://github.com/AdguardTeam/AdGuardHome/issues/3437
|
||||
[#3450]: https://github.com/AdguardTeam/AdGuardHome/issues/3450
|
||||
[#3457]: https://github.com/AdguardTeam/AdGuardHome/issues/3457
|
||||
[#3506]: https://github.com/AdguardTeam/AdGuardHome/issues/3506
|
||||
|
||||
|
||||
|
||||
|
||||
619
client/package-lock.json
generated
vendored
619
client/package-lock.json
generated
vendored
@@ -70,15 +70,6 @@
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
|
||||
"integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
@@ -1188,16 +1179,6 @@
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"@babel/runtime-corejs3": {
|
||||
"version": "7.9.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.9.6.tgz",
|
||||
"integrity": "sha512-6toWAfaALQjt3KMZQc6fABqZwUDDuWzz+cAfPhqyEnzxvdWOAkjwPNxgF8xlmo7OWLsSjaKjsskpKHRLaMArOA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-js-pure": "^3.0.0",
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"@babel/template": {
|
||||
"version": "7.8.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz",
|
||||
@@ -1909,11 +1890,6 @@
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"kind-of": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
|
||||
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA=="
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
|
||||
@@ -2875,13 +2851,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"array-includes": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz",
|
||||
"integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==",
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz",
|
||||
"integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.0",
|
||||
"es-abstract": "^1.18.0-next.2",
|
||||
"get-intrinsic": "^1.1.1",
|
||||
"is-string": "^1.0.5"
|
||||
}
|
||||
},
|
||||
@@ -2907,13 +2885,26 @@
|
||||
"dev": true
|
||||
},
|
||||
"array.prototype.flat": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz",
|
||||
"integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==",
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz",
|
||||
"integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind": "^1.0.0",
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.0-next.1"
|
||||
"es-abstract": "^1.18.0-next.1"
|
||||
}
|
||||
},
|
||||
"array.prototype.flatmap": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz",
|
||||
"integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind": "^1.0.0",
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.18.0-next.1",
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"arrify": {
|
||||
@@ -3197,11 +3188,6 @@
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
|
||||
@@ -3863,6 +3849,15 @@
|
||||
"unset-value": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
"integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"get-intrinsic": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"caller-callsite": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
|
||||
@@ -4325,12 +4320,6 @@
|
||||
"integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
|
||||
"dev": true
|
||||
},
|
||||
"contains-path": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
|
||||
"integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=",
|
||||
"dev": true
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
|
||||
@@ -4550,12 +4539,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"core-js-pure": {
|
||||
"version": "3.6.5",
|
||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz",
|
||||
"integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==",
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
@@ -5421,21 +5404,27 @@
|
||||
}
|
||||
},
|
||||
"es-abstract": {
|
||||
"version": "1.17.5",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
|
||||
"integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
|
||||
"version": "1.18.5",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.5.tgz",
|
||||
"integrity": "sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==",
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"es-to-primitive": "^1.2.1",
|
||||
"function-bind": "^1.1.1",
|
||||
"get-intrinsic": "^1.1.1",
|
||||
"has": "^1.0.3",
|
||||
"has-symbols": "^1.0.1",
|
||||
"is-callable": "^1.1.5",
|
||||
"is-regex": "^1.0.5",
|
||||
"object-inspect": "^1.7.0",
|
||||
"has-symbols": "^1.0.2",
|
||||
"internal-slot": "^1.0.3",
|
||||
"is-callable": "^1.2.3",
|
||||
"is-negative-zero": "^2.0.1",
|
||||
"is-regex": "^1.1.3",
|
||||
"is-string": "^1.0.6",
|
||||
"object-inspect": "^1.11.0",
|
||||
"object-keys": "^1.1.1",
|
||||
"object.assign": "^4.1.0",
|
||||
"string.prototype.trimleft": "^2.1.1",
|
||||
"string.prototype.trimright": "^2.1.1"
|
||||
"object.assign": "^4.1.2",
|
||||
"string.prototype.trimend": "^1.0.4",
|
||||
"string.prototype.trimstart": "^1.0.4",
|
||||
"unbox-primitive": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"es-to-primitive": {
|
||||
@@ -5658,22 +5647,38 @@
|
||||
}
|
||||
},
|
||||
"eslint-import-resolver-node": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz",
|
||||
"integrity": "sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==",
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
|
||||
"integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^2.6.9",
|
||||
"resolve": "^1.13.1"
|
||||
"debug": "^3.2.7",
|
||||
"resolve": "^1.20.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5741,15 +5746,6 @@
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
|
||||
"integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
@@ -5837,44 +5833,53 @@
|
||||
}
|
||||
},
|
||||
"eslint-module-utils": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz",
|
||||
"integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==",
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.2.tgz",
|
||||
"integrity": "sha512-QG8pcgThYOuqxupd06oYTZoNOGaUdTY1PqK+oS6ElF6vs4pBdk/aYxFVQQXzcrAqp9m7cl7lb2ubazX+g16k2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^2.6.9",
|
||||
"debug": "^3.2.7",
|
||||
"pkg-dir": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-import": {
|
||||
"version": "2.20.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz",
|
||||
"integrity": "sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg==",
|
||||
"version": "2.24.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.1.tgz",
|
||||
"integrity": "sha512-KSFWhNxPH8OGJwpRJJs+Z7I0a13E2iFQZJIvSnCu6KUs4qmgAm3xN9GYBCSoiGWmwA7gERZPXqYQjcoCROnYhQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-includes": "^3.0.3",
|
||||
"array.prototype.flat": "^1.2.1",
|
||||
"contains-path": "^0.1.0",
|
||||
"array-includes": "^3.1.3",
|
||||
"array.prototype.flat": "^1.2.4",
|
||||
"debug": "^2.6.9",
|
||||
"doctrine": "1.5.0",
|
||||
"eslint-import-resolver-node": "^0.3.2",
|
||||
"eslint-module-utils": "^2.4.1",
|
||||
"doctrine": "^2.1.0",
|
||||
"eslint-import-resolver-node": "^0.3.6",
|
||||
"eslint-module-utils": "^2.6.2",
|
||||
"find-up": "^2.0.0",
|
||||
"has": "^1.0.3",
|
||||
"is-core-module": "^2.6.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"object.values": "^1.1.0",
|
||||
"read-pkg-up": "^2.0.0",
|
||||
"resolve": "^1.12.0"
|
||||
"object.values": "^1.1.4",
|
||||
"pkg-up": "^2.0.0",
|
||||
"read-pkg-up": "^3.0.0",
|
||||
"resolve": "^1.20.0",
|
||||
"tsconfig-paths": "^3.10.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -5887,20 +5892,23 @@
|
||||
}
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
|
||||
"integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esutils": "^2.0.2",
|
||||
"isarray": "^1.0.0"
|
||||
"esutils": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
||||
"dev": true
|
||||
"resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5930,22 +5938,23 @@
|
||||
}
|
||||
},
|
||||
"eslint-plugin-react": {
|
||||
"version": "7.20.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.20.0.tgz",
|
||||
"integrity": "sha512-rqe1abd0vxMjmbPngo4NaYxTcR3Y4Hrmc/jg4T+sYz63yqlmJRknpEQfmWY+eDWPuMmix6iUIK+mv0zExjeLgA==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.24.0.tgz",
|
||||
"integrity": "sha512-KJJIx2SYx7PBx3ONe/mEeMz4YE0Lcr7feJTCMyyKb/341NcjuAgim3Acgan89GfPv7nxXK2+0slu0CWXYM4x+Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-includes": "^3.1.1",
|
||||
"array-includes": "^3.1.3",
|
||||
"array.prototype.flatmap": "^1.2.4",
|
||||
"doctrine": "^2.1.0",
|
||||
"has": "^1.0.3",
|
||||
"jsx-ast-utils": "^2.2.3",
|
||||
"object.entries": "^1.1.1",
|
||||
"object.fromentries": "^2.0.2",
|
||||
"object.values": "^1.1.1",
|
||||
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"object.entries": "^1.1.4",
|
||||
"object.fromentries": "^2.0.4",
|
||||
"object.values": "^1.1.4",
|
||||
"prop-types": "^15.7.2",
|
||||
"resolve": "^1.15.1",
|
||||
"string.prototype.matchall": "^4.0.2",
|
||||
"xregexp": "^4.3.0"
|
||||
"resolve": "^2.0.0-next.3",
|
||||
"string.prototype.matchall": "^4.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"doctrine": {
|
||||
@@ -5957,6 +5966,16 @@
|
||||
"esutils": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"jsx-ast-utils": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
|
||||
"integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-includes": "^3.1.2",
|
||||
"object.assign": "^4.1.2"
|
||||
}
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
@@ -5967,6 +5986,16 @@
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
}
|
||||
},
|
||||
"resolve": {
|
||||
"version": "2.0.0-next.3",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz",
|
||||
"integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6883,6 +6912,16 @@
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true
|
||||
},
|
||||
"get-intrinsic": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
||||
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3",
|
||||
"has-symbols": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"get-package-type": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
|
||||
@@ -7191,15 +7230,28 @@
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"has-bigints": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
|
||||
"integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
|
||||
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
|
||||
"integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
|
||||
},
|
||||
"has-tostringtag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
|
||||
"integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
|
||||
"requires": {
|
||||
"has-symbols": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"has-value": {
|
||||
"version": "1.0.0",
|
||||
@@ -7824,14 +7876,13 @@
|
||||
}
|
||||
},
|
||||
"internal-slot": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz",
|
||||
"integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==",
|
||||
"dev": true,
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
|
||||
"integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
|
||||
"requires": {
|
||||
"es-abstract": "^1.17.0-next.1",
|
||||
"get-intrinsic": "^1.1.0",
|
||||
"has": "^1.0.3",
|
||||
"side-channel": "^1.0.2"
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"interpret": {
|
||||
@@ -7929,6 +7980,14 @@
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
|
||||
},
|
||||
"is-bigint": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
|
||||
"integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
|
||||
"requires": {
|
||||
"has-bigints": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
|
||||
@@ -7938,6 +7997,15 @@
|
||||
"binary-extensions": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-boolean-object": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
|
||||
"integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
@@ -7945,9 +8013,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"is-callable": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
|
||||
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q=="
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
|
||||
"integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w=="
|
||||
},
|
||||
"is-ci": {
|
||||
"version": "2.0.0",
|
||||
@@ -7958,6 +8026,15 @@
|
||||
"ci-info": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"is-core-module": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz",
|
||||
"integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"is-data-descriptor": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
|
||||
@@ -8060,6 +8137,11 @@
|
||||
"integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
|
||||
"dev": true
|
||||
},
|
||||
"is-negative-zero": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
|
||||
"integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w=="
|
||||
},
|
||||
"is-number": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
|
||||
@@ -8080,6 +8162,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"is-number-object": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
|
||||
"integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==",
|
||||
"requires": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-path-cwd": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
|
||||
@@ -8131,11 +8221,12 @@
|
||||
"integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ=="
|
||||
},
|
||||
"is-regex": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
|
||||
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
|
||||
"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
|
||||
"requires": {
|
||||
"has": "^1.0.3"
|
||||
"call-bind": "^1.0.2",
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-regexp": {
|
||||
@@ -8150,10 +8241,12 @@
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
|
||||
},
|
||||
"is-string": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
|
||||
"integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==",
|
||||
"dev": true
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
|
||||
"integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
|
||||
"requires": {
|
||||
"has-tostringtag": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"is-symbol": {
|
||||
"version": "1.0.3",
|
||||
@@ -10121,9 +10214,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
|
||||
"integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
|
||||
"integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.5"
|
||||
@@ -10237,24 +10330,25 @@
|
||||
"integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA="
|
||||
},
|
||||
"load-json-file": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
|
||||
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
|
||||
"integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"parse-json": "^2.2.0",
|
||||
"pify": "^2.0.0",
|
||||
"parse-json": "^4.0.0",
|
||||
"pify": "^3.0.0",
|
||||
"strip-bom": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"parse-json": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
|
||||
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"error-ex": "^1.2.0"
|
||||
"error-ex": "^1.3.1",
|
||||
"json-parse-better-errors": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11327,9 +11421,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"object-inspect": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
|
||||
"integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw=="
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
|
||||
"integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
|
||||
},
|
||||
"object-is": {
|
||||
"version": "1.1.2",
|
||||
@@ -11355,37 +11449,36 @@
|
||||
}
|
||||
},
|
||||
"object.assign": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
|
||||
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
|
||||
"integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
|
||||
"requires": {
|
||||
"define-properties": "^1.1.2",
|
||||
"function-bind": "^1.1.1",
|
||||
"has-symbols": "^1.0.0",
|
||||
"object-keys": "^1.0.11"
|
||||
"call-bind": "^1.0.0",
|
||||
"define-properties": "^1.1.3",
|
||||
"has-symbols": "^1.0.1",
|
||||
"object-keys": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"object.entries": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.1.tgz",
|
||||
"integrity": "sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz",
|
||||
"integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.0-next.1",
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3"
|
||||
"es-abstract": "^1.18.2"
|
||||
}
|
||||
},
|
||||
"object.fromentries": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.2.tgz",
|
||||
"integrity": "sha512-r3ZiBH7MQppDJVLx6fhD618GKNG40CZYH9wgwdhKxBDDbQgjeWGGd4AtkZad84d291YxvWe7bJGuE65Anh0dxQ==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz",
|
||||
"integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.0-next.1",
|
||||
"function-bind": "^1.1.1",
|
||||
"es-abstract": "^1.18.0-next.2",
|
||||
"has": "^1.0.3"
|
||||
}
|
||||
},
|
||||
@@ -11409,15 +11502,14 @@
|
||||
}
|
||||
},
|
||||
"object.values": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz",
|
||||
"integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==",
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz",
|
||||
"integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.0-next.1",
|
||||
"function-bind": "^1.1.1",
|
||||
"has": "^1.0.3"
|
||||
"es-abstract": "^1.18.2"
|
||||
}
|
||||
},
|
||||
"obuf": {
|
||||
@@ -11791,9 +11883,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
},
|
||||
"pinkie": {
|
||||
@@ -12718,35 +12810,35 @@
|
||||
}
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
|
||||
"integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
|
||||
"integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"load-json-file": "^2.0.0",
|
||||
"load-json-file": "^4.0.0",
|
||||
"normalize-package-data": "^2.3.2",
|
||||
"path-type": "^2.0.0"
|
||||
"path-type": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"path-type": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
|
||||
"integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
||||
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pify": "^2.0.0"
|
||||
"pify": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"read-pkg-up": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
|
||||
"integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
|
||||
"integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"find-up": "^2.0.0",
|
||||
"read-pkg": "^2.0.0"
|
||||
"read-pkg": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
@@ -12894,12 +12986,12 @@
|
||||
}
|
||||
},
|
||||
"regexp.prototype.flags": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
|
||||
"integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz",
|
||||
"integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==",
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.0-next.1"
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"regexpp": {
|
||||
@@ -13572,13 +13664,13 @@
|
||||
"optional": true
|
||||
},
|
||||
"side-channel": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz",
|
||||
"integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==",
|
||||
"dev": true,
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"requires": {
|
||||
"es-abstract": "^1.17.0-next.1",
|
||||
"object-inspect": "^1.7.0"
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"signal-exit": {
|
||||
@@ -14101,6 +14193,15 @@
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"string-length": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz",
|
||||
@@ -14163,64 +14264,37 @@
|
||||
}
|
||||
},
|
||||
"string.prototype.matchall": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz",
|
||||
"integrity": "sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==",
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.5.tgz",
|
||||
"integrity": "sha512-Z5ZaXO0svs0M2xd/6By3qpeKpLKd9mO4v4q3oMEQrk8Ck4xOD5d5XeBOOjGrmVZZ/AHB1S0CgG4N5r1G9N3E2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.0",
|
||||
"has-symbols": "^1.0.1",
|
||||
"internal-slot": "^1.0.2",
|
||||
"regexp.prototype.flags": "^1.3.0",
|
||||
"side-channel": "^1.0.2"
|
||||
"es-abstract": "^1.18.2",
|
||||
"get-intrinsic": "^1.1.1",
|
||||
"has-symbols": "^1.0.2",
|
||||
"internal-slot": "^1.0.3",
|
||||
"regexp.prototype.flags": "^1.3.1",
|
||||
"side-channel": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimend": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
|
||||
"integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
|
||||
"integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimleft": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz",
|
||||
"integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==",
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5",
|
||||
"string.prototype.trimstart": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimright": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz",
|
||||
"integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==",
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5",
|
||||
"string.prototype.trimend": "^1.0.0"
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"string.prototype.trimstart": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
|
||||
"integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
|
||||
"integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
|
||||
"requires": {
|
||||
"define-properties": "^1.1.3",
|
||||
"es-abstract": "^1.17.5"
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
"call-bind": "^1.0.2",
|
||||
"define-properties": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"stringify-entities": {
|
||||
@@ -15111,6 +15185,17 @@
|
||||
"integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
|
||||
"dev": true
|
||||
},
|
||||
"tsconfig-paths": {
|
||||
"version": "3.10.1",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz",
|
||||
"integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"json5": "^2.2.0",
|
||||
"minimist": "^1.2.0",
|
||||
"strip-bom": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||
@@ -15194,6 +15279,17 @@
|
||||
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.22.tgz",
|
||||
"integrity": "sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q=="
|
||||
},
|
||||
"unbox-primitive": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
|
||||
"integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1",
|
||||
"has-bigints": "^1.0.1",
|
||||
"has-symbols": "^1.0.2",
|
||||
"which-boxed-primitive": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"unherit": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
|
||||
@@ -16247,6 +16343,18 @@
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"which-boxed-primitive": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
|
||||
"integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
|
||||
"requires": {
|
||||
"is-bigint": "^1.0.1",
|
||||
"is-boolean-object": "^1.1.0",
|
||||
"is-number-object": "^1.0.4",
|
||||
"is-string": "^1.0.5",
|
||||
"is-symbol": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"which-module": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
|
||||
@@ -16361,15 +16469,6 @@
|
||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||
"dev": true
|
||||
},
|
||||
"xregexp": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz",
|
||||
"integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime-corejs3": "^7.8.3"
|
||||
}
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
|
||||
4
client/package.json
vendored
4
client/package.json
vendored
@@ -64,9 +64,9 @@
|
||||
"eslint-config-airbnb": "^18.1.0",
|
||||
"eslint-import-resolver-webpack": "^0.12.1",
|
||||
"eslint-loader": "^4.0.2",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||
"eslint-plugin-react": "^7.20.0",
|
||||
"eslint-plugin-react": "^7.24.0",
|
||||
"eslint-plugin-react-hooks": "^2.5.0",
|
||||
"file-loader": "6.0.0",
|
||||
"html-webpack-plugin": "^4.3.0",
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "můžete použít <0>DNS razítka</0> pro <1>DNSCrypt</1> nebo <2>DNS skrze HTTPS</2> řešitele",
|
||||
"example_upstream_tcp": "obyčejný DNS (přes TCP)",
|
||||
"all_lists_up_to_date_toast": "Všechny seznamy jsou již aktuální",
|
||||
"updated_upstream_dns_toast": "Aktualizované upstream DNS servery",
|
||||
"updated_upstream_dns_toast": "Odchozí servery byly úspěšně uloženy",
|
||||
"dns_test_ok_toast": "Specifikované DNS servery pracují správně",
|
||||
"dns_test_not_ok_toast": "Server \"{{key}}\": nemohl být použit, zkontrolujte, zda jste ho správně napsali",
|
||||
"unblock": "Odblokovat",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Načítání...",
|
||||
"page_table_footer_text": "Stránka",
|
||||
"rows_table_footer_text": "řádky",
|
||||
"updated_custom_filtering_toast": "Aktualizovaná vlastní pravidla filtrování",
|
||||
"updated_custom_filtering_toast": "Vlastní pravidla byla úspěšně uložena",
|
||||
"rule_removed_from_custom_filtering_toast": "Pravidlo odstraněno z vlastních pravidel filtrování: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Pravidlo přidáno do vlastních pravidel filtrování: {{rule}}",
|
||||
"query_log_response_status": "Status: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Port 53 je často obsazen službami \"DNSStubListener\" nebo \"systemd-resolved\". Přečtěte si <0>tento návod</0> o tom, jak to vyřešit.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home zruší všechny DNS dotazy tohoto klienta.",
|
||||
"client_not_in_allowed_clients": "Tento klient není povolen, protože není na seznamu \"Povolení klienti\".",
|
||||
"experimental": "Experimentální"
|
||||
"experimental": "Experimentální",
|
||||
"use_saved_key": "Použít dříve uložený klíče"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "du kan bruge <0>DNS Stamps</0> til <1>DNSCrypt</1> eller <2>DNS-over-HTTPS</2>-resolvers",
|
||||
"example_upstream_tcp": "almindelig DNS (over TCP)",
|
||||
"all_lists_up_to_date_toast": "Alle lister er allerede opdaterede",
|
||||
"updated_upstream_dns_toast": "Opdaterede upstream DNS-serverene",
|
||||
"updated_upstream_dns_toast": "Upstream-servere er gemt",
|
||||
"dns_test_ok_toast": "Angivne DNS-servere fungerer korrekt",
|
||||
"dns_test_not_ok_toast": "Server \"{{key}}\": Kunne ikke bruges. Tjek, at du har angivet den korrekt",
|
||||
"unblock": "Afblokering",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Indlæser...",
|
||||
"page_table_footer_text": "Side",
|
||||
"rows_table_footer_text": "rækker",
|
||||
"updated_custom_filtering_toast": "Tilpassede filtreringsregler er nu opdateret",
|
||||
"updated_custom_filtering_toast": "Tilpassede regler er gemt",
|
||||
"rule_removed_from_custom_filtering_toast": "Regel fjernet fra de tilpassede filtreringsregler: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Regel føjet til de tilpassede filtreringsregler: {{rule}}",
|
||||
"query_log_response_status": "Status: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Port 53 optages ofte af \"DNSStubListener\" eller \"systemd-resolved\" tjenester. Læs <0>denne instruktion</0> om, hvordan du løser dette.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home vil afbryde alle DNS-forespørgsler fra denne klient.",
|
||||
"client_not_in_allowed_clients": "Klienten er ikke tilladt, fordi den ikke er på listen \"Tilladte klienter\".",
|
||||
"experimental": "Eksperimentel"
|
||||
"experimental": "Eksperimentel",
|
||||
"use_saved_key": "Brug den tidligere gemte nøgle"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "Sie können <0>DNS-Stempel</0> für <1>DNSCrypt</1> oder <2>DNS-over-HTTPS</2> Resolver benutzen",
|
||||
"example_upstream_tcp": "regulärer DNS (über TCP)",
|
||||
"all_lists_up_to_date_toast": "Alle Listen sind bereits auf dem neuesten Stand",
|
||||
"updated_upstream_dns_toast": "Upstream-DNS-Server wurden aktualisiert",
|
||||
"updated_upstream_dns_toast": "Upstream-Server erfolgreich gespeichert",
|
||||
"dns_test_ok_toast": "Angegebene DNS-Server arbeiten ordnungsgemäß",
|
||||
"dns_test_not_ok_toast": "Server „{{key}}“: konnte nicht verwendet werden, bitte überprüfen Sie die korrekte Schreibweise",
|
||||
"unblock": "Entsperren",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Wird geladen …",
|
||||
"page_table_footer_text": "Seite",
|
||||
"rows_table_footer_text": "Reihen",
|
||||
"updated_custom_filtering_toast": "Die benutzerdefinierten Filterregeln wurden aktualisiert",
|
||||
"updated_custom_filtering_toast": "Benutzerdefinierten Filterregeln erfolgreich gespeichert",
|
||||
"rule_removed_from_custom_filtering_toast": "Regel wurde aus den benutzerdefinierten Filterregeln entfernt: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Regel wurde zu den benutzerdefinierten Filterregeln hinzugefügt: {{rule}}",
|
||||
"query_log_response_status": "Status: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Port 53 wird oft von Diensten wie „DNSStubListener” oder „systemresolved” belegt. Bitte lesen Sie <0>diese Anweisung</0>, wie dies behoben werden kann.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home wird alle DNS-Abfragen von diesem Client verwerfen.",
|
||||
"client_not_in_allowed_clients": "Dieser Client ist nicht zugelassen, da dieser nicht in der Liste „Erlaubte Clients” aufgeführt ist.",
|
||||
"experimental": "Experimentell"
|
||||
"experimental": "Experimentell",
|
||||
"use_saved_key": "Zuvor gespeicherten Schlüssel verwenden"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "you can use <0>DNS Stamps</0> for <1>DNSCrypt</1> or <2>DNS-over-HTTPS</2> resolvers",
|
||||
"example_upstream_tcp": "regular DNS (over TCP)",
|
||||
"all_lists_up_to_date_toast": "All lists are already up-to-date",
|
||||
"updated_upstream_dns_toast": "Updated the upstream DNS servers",
|
||||
"updated_upstream_dns_toast": "Upstream servers successfully saved",
|
||||
"dns_test_ok_toast": "Specified DNS servers are working correctly",
|
||||
"dns_test_not_ok_toast": "Server \"{{key}}\": could not be used, please check that you've written it correctly",
|
||||
"unblock": "Unblock",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Loading...",
|
||||
"page_table_footer_text": "Page",
|
||||
"rows_table_footer_text": "rows",
|
||||
"updated_custom_filtering_toast": "Updated the custom filtering rules",
|
||||
"updated_custom_filtering_toast": "Custom rules successfully saved",
|
||||
"rule_removed_from_custom_filtering_toast": "Rule removed from the custom filtering rules: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Rule added to the custom filtering rules: {{rule}}",
|
||||
"query_log_response_status": "Status: {{value}}",
|
||||
@@ -503,6 +503,7 @@
|
||||
"statistics_clear_confirm": "Are you sure you want to clear statistics?",
|
||||
"statistics_retention_confirm": "Are you sure you want to change statistics retention? If you decrease the interval value, some data will be lost",
|
||||
"statistics_cleared": "Statistics successfully cleared",
|
||||
"statistics_enable": "Enable statistics",
|
||||
"interval_hours": "{{count}} hour",
|
||||
"interval_hours_plural": "{{count}} hours",
|
||||
"filters_configuration": "Filters configuration",
|
||||
@@ -613,5 +614,6 @@
|
||||
"port_53_faq_link": "Port 53 is often occupied by \"DNSStubListener\" or \"systemd-resolved\" services. Please read <0>this instruction</0> on how to resolve this.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client.",
|
||||
"client_not_in_allowed_clients": "The client is not allowed because it is not in the \"Allowed clients\" list.",
|
||||
"experimental": "Experimental"
|
||||
"experimental": "Experimental",
|
||||
"use_saved_key": "Use the previously saved key"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "puedes usar <0>DNS Stamps</0> para <1>DNSCrypt</1> o resolutores <2>DNS mediante HTTPS</2>",
|
||||
"example_upstream_tcp": "DNS regular (mediante TCP)",
|
||||
"all_lists_up_to_date_toast": "Todas las listas ya están actualizadas",
|
||||
"updated_upstream_dns_toast": "Servidores DNS de subida actualizados",
|
||||
"updated_upstream_dns_toast": "Servidores de subida guardados correctamente",
|
||||
"dns_test_ok_toast": "Los servidores DNS especificados funcionan correctamente",
|
||||
"dns_test_not_ok_toast": "Servidor \"{{key}}\": no se puede utilizar, por favor revisa si lo has escrito correctamente",
|
||||
"unblock": "Desbloquear",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Cargando...",
|
||||
"page_table_footer_text": "Página",
|
||||
"rows_table_footer_text": "filas",
|
||||
"updated_custom_filtering_toast": "Reglas de filtrado personalizado actualizadas",
|
||||
"updated_custom_filtering_toast": "Reglas de filtrado guardadas correctamente",
|
||||
"rule_removed_from_custom_filtering_toast": "Regla eliminada de las reglas de filtrado personalizado: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Regla añadida a las reglas de filtrado personalizado: {{rule}}",
|
||||
"query_log_response_status": "Estado: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "El puerto 53 suele estar ocupado por los servicios \"DNSStubListener\" o \"systemd-resolved\". Por favor lee <0>esta instrucción</0> sobre cómo resolver esto.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home descartará todas las consultas DNS de este cliente.",
|
||||
"client_not_in_allowed_clients": "El cliente no está permitido porque no está en la lista de \"Clientes permitidos\".",
|
||||
"experimental": "experimental"
|
||||
"experimental": "experimental",
|
||||
"use_saved_key": "Usar la clave guardada previamente"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "vous pouvez utiliser <0>DNS Stamps</0> pour <1>DNSCrypt</1> ou les resolveurs <2>DNS_over_HTTPS</2>",
|
||||
"example_upstream_tcp": "DNS classique (au-dessus de TCP)",
|
||||
"all_lists_up_to_date_toast": "Toutes les listes sont déjà à jour",
|
||||
"updated_upstream_dns_toast": "Les serveurs DNS upstream sont mis à jour",
|
||||
"updated_upstream_dns_toast": "Serveurs en amont enregistrés",
|
||||
"dns_test_ok_toast": "Les serveurs DNS spécifiés fonctionnent correctement",
|
||||
"dns_test_not_ok_toast": "Impossible d'utiliser le serveur « {{key}} »: veuillez vérifier si le nom saisi est bien correct",
|
||||
"unblock": "Débloquer",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Chargement en cours ...",
|
||||
"page_table_footer_text": "Page",
|
||||
"rows_table_footer_text": "lignes",
|
||||
"updated_custom_filtering_toast": "Règles de filtrage d'utilisateur mises à jour",
|
||||
"updated_custom_filtering_toast": "Règles d'utilisateur enregistrées",
|
||||
"rule_removed_from_custom_filtering_toast": "Règle retirée des règles d'utilisateur : {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Règle ajoutée aux règles d'utilisateur : {{rule}}",
|
||||
"query_log_response_status": "Statut : {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Le port 53 est souvent occupé par les services « DNSStubListener » ou « systemd-resolved ». Veuillez lire <0>cette instruction</0> pour savoir comment résoudre ce problème.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home ignorera toutes les requêtes DNS de ce client.",
|
||||
"client_not_in_allowed_clients": "Le client n’est pas autorisé car il ne figure pas dans la liste « Clients autorisés ».",
|
||||
"experimental": "Expérimental"
|
||||
"experimental": "Expérimental",
|
||||
"use_saved_key": "Utiliser la clef précédemment enregistrée"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "használhatja a <0> DNS Stamps</0>-ot a <1>DNSCrypt</1> vagy a <2>DNS-over-HTTPS</2> feloldások érdekében",
|
||||
"example_upstream_tcp": "hagyományos DNS (TCP felett)",
|
||||
"all_lists_up_to_date_toast": "Már minden lista naprakész",
|
||||
"updated_upstream_dns_toast": "Frissítette az upstream DNS-kiszolgálókat",
|
||||
"updated_upstream_dns_toast": "Upstream szerverek sikeresen mentve",
|
||||
"dns_test_ok_toast": "A megadott DNS-kiszolgálók megfelelően működnek",
|
||||
"dns_test_not_ok_toast": "Szerver \"{{key}}\": nem használható, ellenőrizze, hogy helyesen írta-e be",
|
||||
"unblock": "Feloldás",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Betöltés...",
|
||||
"page_table_footer_text": "Oldal",
|
||||
"rows_table_footer_text": "sor",
|
||||
"updated_custom_filtering_toast": "Egyéni szűrőszabályok frissítve",
|
||||
"updated_custom_filtering_toast": "Egyéni szűrőszabályok sikeresen mentve",
|
||||
"rule_removed_from_custom_filtering_toast": "Szabály eltávolítva az egyéni szűrőszabályok közül: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Szabály hozzáadva az egyéni szűrőszabályokhoz: {{rule}}",
|
||||
"query_log_response_status": "Állapot: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Az 53-as portot gyakran a \"DNSStubListener\" vagy a \"systemd-resolved\" (rendszer által feloldott) szolgáltatások használják. Kérjük, olvassa el <0>ezt az útmutatót</0> a probléma megoldásához.",
|
||||
"adg_will_drop_dns_queries": "Az AdGuard Home eldobja az összes DNS kérést erről a kliensről.",
|
||||
"client_not_in_allowed_clients": "Ez a kliens nincs engedélyezve, mivel nincs rajta az \"Engedélyezett kliensek\" listáján.",
|
||||
"experimental": "Kísérleti"
|
||||
"experimental": "Kísérleti",
|
||||
"use_saved_key": "Előzőleg mentett kulcs használata"
|
||||
}
|
||||
|
||||
@@ -48,9 +48,9 @@
|
||||
"range_end_error": "Deve essere maggiore dell'intervallo di inizio",
|
||||
"dhcp_form_gateway_input": "IP Gateway",
|
||||
"dhcp_form_subnet_input": "Maschera di sottorete",
|
||||
"dhcp_form_range_title": "Range indirizzi IP",
|
||||
"dhcp_form_range_start": "Inizio range",
|
||||
"dhcp_form_range_end": "Fine range",
|
||||
"dhcp_form_range_title": "Intervallo di indirizzi IP",
|
||||
"dhcp_form_range_start": "Intervallo iniziale",
|
||||
"dhcp_form_range_end": "Intervallo finale",
|
||||
"dhcp_form_lease_title": "Tempo di lease DHCP (in secondi)",
|
||||
"dhcp_form_lease_input": "Durata lease",
|
||||
"dhcp_interface_select": "Seleziona l'interfaccia DHCP",
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "puoi utilizzare <0>DNS Stamps</0> per <1>DNSCrypt</1> oppure dei risolutori <2>DNS-over-HTTPS</2>",
|
||||
"example_upstream_tcp": "DNS regolari (via TCP)",
|
||||
"all_lists_up_to_date_toast": "Tutte le liste sono aggiornate",
|
||||
"updated_upstream_dns_toast": "Server DNS upstream aggiornati",
|
||||
"updated_upstream_dns_toast": "I server upstream sono stati salvati correttamente",
|
||||
"dns_test_ok_toast": "I server DNS specificati funzionano correttamente",
|
||||
"dns_test_not_ok_toast": "Server \"{{key}}\": non può essere utilizzato, assicurati di averlo digitato correttamente",
|
||||
"unblock": "Sblocca",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Caricamento...",
|
||||
"page_table_footer_text": "Pagina",
|
||||
"rows_table_footer_text": "righe",
|
||||
"updated_custom_filtering_toast": "Le regole dei filtri personalizzate sono state aggiornate",
|
||||
"updated_custom_filtering_toast": "Le regole personalizzate sono state correttamente salvate",
|
||||
"rule_removed_from_custom_filtering_toast": "Regola rimossa dalle regole dei filtri personalizzate: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Regola aggiunta alle regole dei filtri personalizzate: {{rule}}",
|
||||
"query_log_response_status": "Stato: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "La Porta 53 è spesso occupata dai servizi \"DNSStubListener\" o \"systemd-resolved\". Si prega di leggere <0>queste istruzioni</0> per risolvere il problema.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home eliminerà tutte le richieste DNS da questo client.",
|
||||
"client_not_in_allowed_clients": "Il client non è consentito perché non è nell'elenco \"Client consentiti\".",
|
||||
"experimental": "Sperimentale"
|
||||
"experimental": "Sperimentale",
|
||||
"use_saved_key": "Utilizza la chiave salvata in precedenza"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "<1>DNSCrypt</1> または <2>DNS-over-HTTPS</2> リゾルバのために <0>DNS Stamps</0> を使えます",
|
||||
"example_upstream_tcp": "通常のDNS(TCPでの問い合わせ)",
|
||||
"all_lists_up_to_date_toast": "すべてのリストは既に最新です",
|
||||
"updated_upstream_dns_toast": "上流DNSサーバを更新しました",
|
||||
"updated_upstream_dns_toast": "上流DNSサーバを保存しました。",
|
||||
"dns_test_ok_toast": "指定されたDNSサーバは正しく動作しています",
|
||||
"dns_test_not_ok_toast": "サーバ \"{{key}}\": 使用できませんでした。正しく入力されているかどうかを確認してください",
|
||||
"unblock": "ブロック解除",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "読み込み中…",
|
||||
"page_table_footer_text": "ページ",
|
||||
"rows_table_footer_text": "行",
|
||||
"updated_custom_filtering_toast": "カスタム・フィルタリングルールを更新しました",
|
||||
"updated_custom_filtering_toast": "カスタムルールを保存しました。",
|
||||
"rule_removed_from_custom_filtering_toast": "ルールをカスタム・フィルタリングルールから除去しました {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "ルールをカスタム・フィルタリングルールに追加しました {{rule}}",
|
||||
"query_log_response_status": "ステータス: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "多くの場合、ポート53は \"DNSStubListener\" または \"systemd-resolved\" サービスによって利用されています。これを解決する方法については、<0>この手順</0>をお読みください。",
|
||||
"adg_will_drop_dns_queries": "AdGuard Homeは、このクライアントからすべてのDNSクエリを落とします。",
|
||||
"client_not_in_allowed_clients": "「許可されたクライアント」リストにないため、このクライアントは許可されていません。",
|
||||
"experimental": "実験用"
|
||||
"experimental": "実験用",
|
||||
"use_saved_key": "以前に保存したキーを使用する"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "<1>DNSCrypt</1>나 <2>DNS-over-HTTPS</2> 리졸버를 위해 <0>DNS 스탬프</0>를 사용할 수 있습니다",
|
||||
"example_upstream_tcp": "사용자 지정 DNS (TCP를 통한 접속)",
|
||||
"all_lists_up_to_date_toast": "모든 리스트가 이미 최신입니다",
|
||||
"updated_upstream_dns_toast": "업스트림 DNS 서버를 업데이트하였습니다",
|
||||
"updated_upstream_dns_toast": "업스트림 서버가 성공적으로 저장되었습니다",
|
||||
"dns_test_ok_toast": "특정 DNS 서버들은 정상적으로 동작 중입니다",
|
||||
"dns_test_not_ok_toast": "서버 \"{{key}}\": 사용할 수 없습니다, 제대로 작성했는지 확인하세요.",
|
||||
"unblock": "차단 해제",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "로딩중...",
|
||||
"page_table_footer_text": "페이지",
|
||||
"rows_table_footer_text": "행",
|
||||
"updated_custom_filtering_toast": "사용자 정의 필터링 규칙 업데이트",
|
||||
"updated_custom_filtering_toast": "사용자 정의 규칙이 성공적으로 저장되었습니다",
|
||||
"rule_removed_from_custom_filtering_toast": "사용자 정의 필터링 규칙에서 규칙 제거 {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "사용자 정의 필터링 규칙에 추가된 규칙 {{rule}}",
|
||||
"query_log_response_status": "상태: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "53번 포트는 보통 \"DNSStubListener\"나 \"systemd-resolved\" 서비스가 이미 사용하고 있습니다. 이 문제에 대한 해결 방법을 <0>설명</0>에서 찾아보세요.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home은 이 클라이언트에서 모든 DNS 쿼리를 삭제합니다.",
|
||||
"client_not_in_allowed_clients": "이 클라이언트는 허용된 클라이언트 목록에 없으므로 허용되지 않습니다.",
|
||||
"experimental": "실험"
|
||||
"experimental": "실험",
|
||||
"use_saved_key": "이전에 저장했던 키 사용하기"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "je kunt <0>DNS Stamps</0> voor <1>DNSCrypt</1> of <2>DNS-via-HTTPS</2> oplossingen gebruiken",
|
||||
"example_upstream_tcp": "standaard DNS (over TCP)",
|
||||
"all_lists_up_to_date_toast": "Alle lijsten zijn reeds up-to-date",
|
||||
"updated_upstream_dns_toast": "De upstream DNS-servers zijn bijgewerkt",
|
||||
"updated_upstream_dns_toast": "Upstream-servers succesvol opgeslagen",
|
||||
"dns_test_ok_toast": "Opgegeven DNS-servers werken correct",
|
||||
"dns_test_not_ok_toast": "Server \"{{key}}\": kon niet worden gebruikt, controleer of je het correct hebt geschreven",
|
||||
"unblock": "Deblokkeren",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Laden...",
|
||||
"page_table_footer_text": "Pagina",
|
||||
"rows_table_footer_text": "rijen",
|
||||
"updated_custom_filtering_toast": "Aangepaste filter regels zijn bijgewerkt",
|
||||
"updated_custom_filtering_toast": "Aangepaste regels succesvol opgeslagen",
|
||||
"rule_removed_from_custom_filtering_toast": "Regel verwijderd uit de aangepaste filterregels: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Regel toegevoegd aan de aangepaste filterregels: {{rule}}",
|
||||
"query_log_response_status": "Status: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Poort 53 wordt vaak gebruikt door services als DNSStubListener- of de systeem DNS-resolver. Lees a.u.b. <0>deze instructie</0> hoe dit is op te lossen.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home zal alle DNS verzoeken van deze toepassing/dit systeem negeren.",
|
||||
"client_not_in_allowed_clients": "De toepassing is niet toegestaan omdat deze niet in de lijst \"Toegestane toepassingen\" voorkomt.",
|
||||
"experimental": "Experimenteel"
|
||||
"experimental": "Experimenteel",
|
||||
"use_saved_key": "De eerder opgeslagen sleutel gebruiken"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "możesz użyć adresu <0>DNS Stamps</0> dla protokołu <1>DNSCrypt</1> lub <2>DNS-over-HTTPS</2>",
|
||||
"example_upstream_tcp": "zwykły DNS (przez TCP)",
|
||||
"all_lists_up_to_date_toast": "Wszystkie listy są już aktualne",
|
||||
"updated_upstream_dns_toast": "Główne serwery DNS zostały zaktualizowane",
|
||||
"updated_upstream_dns_toast": "Serwery nadrzędne zostały pomyślnie zapisane",
|
||||
"dns_test_ok_toast": "Określone serwery DNS działają poprawnie",
|
||||
"dns_test_not_ok_toast": "Serwer \"{{key}}\": nie można go użyć, sprawdź, czy napisałeś go poprawnie",
|
||||
"unblock": "Odblokuj",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Wczytuję...",
|
||||
"page_table_footer_text": "Strona",
|
||||
"rows_table_footer_text": "wierszy",
|
||||
"updated_custom_filtering_toast": "Zaktualizowano niestandardowe reguły filtrowania",
|
||||
"updated_custom_filtering_toast": "Reguły niestandardowe zapisane pomyślnie",
|
||||
"rule_removed_from_custom_filtering_toast": "Reguła usunięta z niestandardowych reguł filtrowania: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Reguła dodana do niestandardowych reguł filtrowania: {{rule}}",
|
||||
"query_log_response_status": "Status: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Port 53 jest często zajęty przez usługi \"DNSStubListener\" lub \"systemd-resolved\". Przeczytaj <0>tę instrukcję</0> jak to rozwiązać.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home odrzuci zapytanie DNS od tego klienta.",
|
||||
"client_not_in_allowed_clients": "Klient nie jest dozwolony, ponieważ nie ma go na liście „Dozwoleni klienci”.",
|
||||
"experimental": "Funkcja eksperymentalna"
|
||||
"experimental": "Funkcja eksperymentalna",
|
||||
"use_saved_key": "Użyj wcześniej zapisanego klucza"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "você pode usar <0>DNS Stamps</0> para o <1>DNSCrypt</1> ou usar os resolvedores <2>DNS-sobre-HTTPS</2>",
|
||||
"example_upstream_tcp": "DNS regular (através do TCP)",
|
||||
"all_lists_up_to_date_toast": "Todas as listas já estão atualizadas",
|
||||
"updated_upstream_dns_toast": "Atualizado os servidores DNS primário",
|
||||
"updated_upstream_dns_toast": "Servidores DNS primário salvos com sucesso",
|
||||
"dns_test_ok_toast": "Os servidores DNS especificados estão funcionando corretamente",
|
||||
"dns_test_not_ok_toast": "O servidor \"{{key}}\": não pôde ser utilizado. Por favor, verifique se você escreveu corretamente",
|
||||
"unblock": "Desbloquear",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Carregando",
|
||||
"page_table_footer_text": "Página",
|
||||
"rows_table_footer_text": "linhas",
|
||||
"updated_custom_filtering_toast": "Regras de filtragem personalizadas atualizadas",
|
||||
"updated_custom_filtering_toast": "Regras personalizadas salvas com sucesso",
|
||||
"rule_removed_from_custom_filtering_toast": "Regra removida das regras de filtragem personalizadas: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Regra adicionada às regras de filtragem personalizadas: {{rule}}",
|
||||
"query_log_response_status": "Status: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "A porta 53 é frequentemente ocupada por serviços \"DNSStubListener\" ou \"systemd-resolved\". Por favor leia <0>essa instrução</0> para resolver isso.",
|
||||
"adg_will_drop_dns_queries": "O AdGuard Home descartará todas as consultas DNS deste cliente.",
|
||||
"client_not_in_allowed_clients": "O cliente não é permitido porque não está na lista \"Clientes permitidos\".",
|
||||
"experimental": "Experimental"
|
||||
"experimental": "Experimental",
|
||||
"use_saved_key": "Use a chave salva anteriormente"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "pode usar <0>DNS Stamps</0> para o <1>DNSCrypt</1> ou usar os resolvedores <2>DNS-sobre-HTTPS</2>",
|
||||
"example_upstream_tcp": "dNS regular (através do TCP)",
|
||||
"all_lists_up_to_date_toast": "Todas as listas já estão atualizadas",
|
||||
"updated_upstream_dns_toast": "A atualizar os servidores DNS primário",
|
||||
"updated_upstream_dns_toast": "Servidores DNS primário guardados com sucesso",
|
||||
"dns_test_ok_toast": "Os servidores DNS especificados estão a funcionar corretamente",
|
||||
"dns_test_not_ok_toast": "O servidor \"{{key}}\": não pôde ser utilizado. Por favor, verifique se o escreveu corretamente",
|
||||
"unblock": "Desbloquear",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "A carregar...",
|
||||
"page_table_footer_text": "Página",
|
||||
"rows_table_footer_text": "linhas",
|
||||
"updated_custom_filtering_toast": "Regras de filtragem personalizadas atualizadas",
|
||||
"updated_custom_filtering_toast": "Regras personalizadas guardadas com sucesso",
|
||||
"rule_removed_from_custom_filtering_toast": "Regra removida das regras de filtragem personalizadas: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Regra adicionada às regras de filtragem personalizadas: {{rule}}",
|
||||
"query_log_response_status": "Status: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "A porta 53 é frequentemente ocupada por serviços \"DNSStubListener\" ou \"systemd-resolved\". Por favor leia <0>essa instrução</0> para resolver isso.",
|
||||
"adg_will_drop_dns_queries": "O AdGuard Home descartará todas as consultas DNS deste cliente.",
|
||||
"client_not_in_allowed_clients": "O cliente não é permitido porque não está na lista \"Clientes permitidos\".",
|
||||
"experimental": "Experimental"
|
||||
"experimental": "Experimental",
|
||||
"use_saved_key": "Use a chave guardada anteriormente"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "вы можете использовать <0>DNS Stamps</0> для <1>DNSCrypt</1> или <2>DNS-over-HTTPS</2> резолверов",
|
||||
"example_upstream_tcp": "обычный DNS (поверх TCP)",
|
||||
"all_lists_up_to_date_toast": "Все списки уже обновлены",
|
||||
"updated_upstream_dns_toast": "Upstream DNS-серверы обновлены",
|
||||
"updated_upstream_dns_toast": "DNS-серверы успешно обновлены",
|
||||
"dns_test_ok_toast": "Указанные серверы DNS работают корректно",
|
||||
"dns_test_not_ok_toast": "Сервер «{{key}}»: невозможно использовать, проверьте правильность написания",
|
||||
"unblock": "Разблокировать",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Загрузка…",
|
||||
"page_table_footer_text": "Страница",
|
||||
"rows_table_footer_text": "строк",
|
||||
"updated_custom_filtering_toast": "Внесены изменения в пользовательские правила",
|
||||
"updated_custom_filtering_toast": "Пользовательские правила успешно сохранены",
|
||||
"rule_removed_from_custom_filtering_toast": "Пользовательское правило удалено: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Пользовательское правило добавлено: {{rule}}",
|
||||
"query_log_response_status": "Статус: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Порт 53 часто занят службами «DNSStubListener» или «systemd-resolved». Ознакомьтесь с <0>инструкцией</0> о том, как это разрешить.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home AdGuard Home сбросит все DNS-запросы от этого клиента.",
|
||||
"client_not_in_allowed_clients": "Клиент не разрешён, так как его нет в списке «Разрешённых клиентов».",
|
||||
"experimental": "Экспериментальный"
|
||||
"experimental": "Экспериментальный",
|
||||
"use_saved_key": "Использовать сохранённый ранее ключ"
|
||||
}
|
||||
|
||||
@@ -537,5 +537,6 @@
|
||||
"port_53_faq_link": "53 වන කෙවෙනිය බොහෝ විට \"DNSStubListener\" හෝ \"systemd-resolved\" සේවාවන් භාවිතයට ගනු ලැබේ. කරුණාකර මෙය විසඳන්නේ කෙසේද යන්න පිළිබඳ <0>මෙම උපදෙස්</0> කියවන්න.",
|
||||
"adg_will_drop_dns_queries": "ඇඩ්ගාර්ඩ් හෝම් විසින් මෙම අනුග්රාහකයේ සියලුම ව.නා.ප. විමසුම් අතහැර දමනු ඇත.",
|
||||
"client_not_in_allowed_clients": "\"ඉඩ දුන් අනුග්රාහකයින්\" ලැයිස්තුවේ නැති නිසා අනුග්රාහකයට ඉඩ දී නැත.",
|
||||
"experimental": "පරීක්ෂණාත්මක"
|
||||
"experimental": "පරීක්ෂණාත්මක",
|
||||
"use_saved_key": "පෙර සුරැකි යතුර භාවිතා කරන්න"
|
||||
}
|
||||
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Port 53 je často obsadený službami \"DNSStubListener\" alebo \"systemd-resolved\". Prečítajte si <0>tento návod</0> o tom, ako to vyriešiť.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home zruší všetky DNS dopyty od tohto klienta.",
|
||||
"client_not_in_allowed_clients": "Klient nemá povolenie, pretože sa nenachádza v zozname „Povolení klienti“.",
|
||||
"experimental": "Experimentálne"
|
||||
"experimental": "Experimentálne",
|
||||
"use_saved_key": "Použiť predtým uložený kľúč"
|
||||
}
|
||||
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "Vrata 53 pogosto zasedajo storitve 'DNSStubListener' ali 'Sistemsko razrešene storitve'. Preberite <0>to navodilo</0> o tem, kako to rešiti.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home bo izpustil vse poizvedbe DNS iz tega odjemalca.",
|
||||
"client_not_in_allowed_clients": "Odjemalec ni dovoljen, ker ga ni na seznamu \"Dovoljeni odjemalci\".",
|
||||
"experimental": "Eksperimentalno"
|
||||
"experimental": "Eksperimentalno",
|
||||
"use_saved_key": "Uporabi prej shranjeni ključ"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"client_settings": "Klientinställningar",
|
||||
"bootstrap_dns": "Bootstrap-DNS-servrar",
|
||||
"bootstrap_dns_desc": "Bootstrap-DNS-servrar används för att slå upp DoH/DoT-resolvrarnas IP-adresser som du specificerat som uppström.",
|
||||
"local_ptr_placeholder": "Ange en serveradress per rad",
|
||||
"check_dhcp_servers": "Letar efter DHCP-servrar",
|
||||
"enabled_dhcp": "DHCP-server aktiverad",
|
||||
"disabled_dhcp": "Dhcp-server avaktiverad",
|
||||
@@ -102,7 +103,7 @@
|
||||
"last_time_updated_table_header": "Uppdaterades senast",
|
||||
"actions_table_header": "Åtgärder",
|
||||
"edit_table_action": "Redigera",
|
||||
"delete_table_action": "Ta bort",
|
||||
"delete_table_action": "Radera",
|
||||
"filters_and_hosts_hint": "AdGuard tillämpar grundläggande annonsblockeringsregler och värdfiltersyntaxer",
|
||||
"cancel_btn": "Avbryt",
|
||||
"enter_name_hint": "Skriv in namn",
|
||||
@@ -175,7 +176,7 @@
|
||||
"install_auth_username": "Användarnamn",
|
||||
"install_auth_password": "Lösenord",
|
||||
"install_auth_confirm": "Bekräfta lösenord",
|
||||
"install_auth_username_enter": "Skriv in användarnamn",
|
||||
"install_auth_username_enter": "Ange användarnamn",
|
||||
"install_auth_password_enter": "Skriv in lösenord",
|
||||
"install_step": "Steg",
|
||||
"install_devices_title": "Ställ in dina enheter",
|
||||
@@ -265,6 +266,7 @@
|
||||
"form_enter_ip": "Skriv in IP",
|
||||
"form_enter_mac": "Skriv in MAC",
|
||||
"form_client_name": "Skriv in klientnamn",
|
||||
"name": "Namn",
|
||||
"client_global_settings": "Använda globala inställningar",
|
||||
"client_deleted": "Klient \"{{key}}\" har raderats",
|
||||
"client_added": "Klient \"{{key}}\" har lagts till",
|
||||
@@ -301,11 +303,14 @@
|
||||
"setup_dns_notice": "För att kunna använda <1>DNS-över-HTTPS</1> eller <1>DNS-över-TLS</1>, behöver du <0>konfigurera Kryptering</0> i AdGuard Home-inställningar.",
|
||||
"rewrite_added": "DNS-omskrivning för \"{{key}}\" lyckad",
|
||||
"rewrite_deleted": "DNS-omskrivning för \"{{key}}\" har tagits bort",
|
||||
"interval_6_hour": "6 timmar",
|
||||
"interval_24_hour": "24 timmar",
|
||||
"interval_days": "{{count}} dag",
|
||||
"interval_days_plural": "{{count}} dagar",
|
||||
"domain": "Domän",
|
||||
"answer": "Svar",
|
||||
"statistics_retention_desc": "Om du minskar intervallet kommer viss data att gå förlorad",
|
||||
"statistics_clear": " Rensa statistik",
|
||||
"statistics_clear": "Rensa statistik",
|
||||
"statistics_clear_confirm": "Är du säker på att du vill radera statistiken?",
|
||||
"statistics_retention_confirm": "Är du säker på att du vill ändra retentionstiden för statistik? Om du minskar intervallet kommer viss data att gå förlorad",
|
||||
"statistics_cleared": "Statistiken har rensats",
|
||||
@@ -329,7 +334,9 @@
|
||||
"descr": "Beskrivning",
|
||||
"whois": "Whois",
|
||||
"filtering_rules_learn_more": "<0>Mer info</0> om att skapa dina egna blockeringslistor för värdar.",
|
||||
"try_again": "Försök igen",
|
||||
"show_blocked_responses": "Blockerade",
|
||||
"blocked_adult_websites": "Blockerade vuxensajter",
|
||||
"blocked_threats": "Blockerade hot"
|
||||
"blocked_threats": "Blockerade hot",
|
||||
"use_saved_key": "Använd den tidigare sparade nyckeln"
|
||||
}
|
||||
|
||||
@@ -95,8 +95,8 @@
|
||||
"protocol": "Protokol",
|
||||
"on": "AÇIK",
|
||||
"off": "KAPALI",
|
||||
"copyright": "Telif hakkı",
|
||||
"homepage": "Ana sayfa",
|
||||
"copyright": "Telif Hakkı",
|
||||
"homepage": "Ana Sayfa",
|
||||
"report_an_issue": "Bir sorun bildir",
|
||||
"privacy_policy": "Gizlilik Politikası",
|
||||
"enable_protection": "Korumayı etkinleştir",
|
||||
@@ -105,9 +105,9 @@
|
||||
"disabled_protection": "Koruma durduruldu",
|
||||
"refresh_statics": "İstatistikleri yenile",
|
||||
"dns_query": "DNS Sorguları",
|
||||
"blocked_by": "<0>Filtreler tarafından engellendi</0>",
|
||||
"stats_malware_phishing": "Kötü amaçlı yazılım ve kimlik avı engellendi",
|
||||
"stats_adult": "Yetişkin içerikli site engellendi",
|
||||
"blocked_by": "<0>Filtreler tarafından engellenen</0>",
|
||||
"stats_malware_phishing": "Engellenen kötü amaçlı yazılım ve kimlik avı",
|
||||
"stats_adult": "Engellenen yetişkin içerikli siteler",
|
||||
"stats_query_domain": "En fazla sorgulanan alan adları",
|
||||
"for_last_24_hours": "son 24 saat içindekiler",
|
||||
"for_last_days": "son {{count}} gün boyunca",
|
||||
@@ -129,7 +129,7 @@
|
||||
"enforced_save_search": "Uygulanan güvenli arama",
|
||||
"number_of_dns_query_to_safe_search": "Güvenli Aramanın uygulandığı arama motorlarına gönderilen DNS isteklerinin sayısı",
|
||||
"average_processing_time": "Ortalama işlem süresi",
|
||||
"average_processing_time_hint": "Bir DNS isteğinin mili saniye cinsinden ortalama işlem süresi",
|
||||
"average_processing_time_hint": "Bir DNS isteğinin milisaniye cinsinden ortalama işlem süresi",
|
||||
"block_domain_use_filters_and_hosts": "Filtre ve ana bilgisayar listelerini kullanarak alan adlarını engelle",
|
||||
"filters_block_toggle_hint": "<a>Filtreler</a> sayfasından engelleme kurallarını ayarlayabilirsiniz.",
|
||||
"use_adguard_browsing_sec": "AdGuard gezinti koruması web hizmetini kullan",
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "<1>DNSCrypt</1> veya <2>DNS-over-HTTPS</2> çözümleyicileri için <0>DNS Damgaları</0> kullanabilirsiniz",
|
||||
"example_upstream_tcp": "normal DNS (TCP üzerinden)",
|
||||
"all_lists_up_to_date_toast": "Tüm listeler güncel durumda",
|
||||
"updated_upstream_dns_toast": "Üst DNS sunucuları güncellendi",
|
||||
"updated_upstream_dns_toast": "Üst sunucular başarıyla kaydedildi",
|
||||
"dns_test_ok_toast": "Belirtilen DNS sunucuları düzgün çalışıyor",
|
||||
"dns_test_not_ok_toast": "Sunucu \"{{key}}\": kullanılamıyor, lütfen doğru yazdığınızdan emin olun",
|
||||
"unblock": "Engeli kaldır",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "Yükleniyor...",
|
||||
"page_table_footer_text": "Sayfa",
|
||||
"rows_table_footer_text": "satır",
|
||||
"updated_custom_filtering_toast": "Özel filtreleme kuralları güncellendi",
|
||||
"updated_custom_filtering_toast": "Özel kurallar başarıyla kaydedildi",
|
||||
"rule_removed_from_custom_filtering_toast": "Özel filtreleme kurallarından kaldırıldı: {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "Özel filtreleme kurallarına eklendi: {{rule}}",
|
||||
"query_log_response_status": "Durum: {{value}}",
|
||||
@@ -352,7 +352,7 @@
|
||||
"encryption_config_saved": "Şifreleme yapılandırması kaydedildi",
|
||||
"encryption_server": "Sunucu adı",
|
||||
"encryption_server_enter": "Alan adınızı girin",
|
||||
"encryption_server_desc": "HTTPS kullanmak için SSL sertifikanızla veya Willcard sertifikanızla eşleşen sunucu adını girmeniz gerekir. Bu alan ayarlanmazsa, herhangi bir alan adının TLS bağlantılarını kabul eder.",
|
||||
"encryption_server_desc": "HTTPS kullanmak için SSL sertifikanızla veya joker sertifikanızla eşleşen sunucu adını girmeniz gerekir. Bu alan ayarlanmazsa, herhangi bir alan adının TLS bağlantılarını kabul eder.",
|
||||
"encryption_redirect": "Otomatik olarak HTTPS'e yönlendir",
|
||||
"encryption_redirect_desc": "Etkinleştirirseniz, AdGuard Home sizi HTTP adresi yerine HTTPS adresine yönlendirir.",
|
||||
"encryption_https": "HTTPS bağlantı noktası",
|
||||
@@ -362,7 +362,7 @@
|
||||
"encryption_doq": "DNS-over-QUIC bağlantı noktası",
|
||||
"encryption_doq_desc": "Bu bağlantı noktası yapılandırılırsa, AdGuard Home, DNS-over-QUIC sunucusunu bu bağlantı noktası üzerinden çalıştıracaktır. Bu özellik deneme aşamasındadır ve güvenilir olmayabilir. Ayrıca, şu anda bu özelliği destekleyen çok fazla istemci yok.",
|
||||
"encryption_certificates": "Sertifikalar",
|
||||
"encryption_certificates_desc": "Şifrelemeyi kullanmak için alan adınız için geçerli bir SSL sertifika zinciri sağlamanız gerekir. <0>{{link}}</0> adresinden ücretsiz bir sertifika alabilir veya güvenilir Sertifika Yetkililerinden satın alabilirsiniz.",
|
||||
"encryption_certificates_desc": "Şifrelemeyi kullanmak için alan adınıza geçerli bir SSL sertifika zinciri sağlamanız gerekir. <0>{{link}}</0> adresinden ücretsiz bir sertifika alabilir veya güvenilir Sertifika Yetkililerinden satın alabilirsiniz.",
|
||||
"encryption_certificates_input": "PEM biçimindeki sertifikalarınızı kopyalayıp buraya yapıştırın.",
|
||||
"encryption_status": "Durum",
|
||||
"encryption_expire": "Bitiş tarihi",
|
||||
@@ -476,7 +476,7 @@
|
||||
"blocked_services_saved": "Engellenen hizmetler başarıyla kaydedildi",
|
||||
"blocked_services_global": "Genel olarak engellenen hizmetleri kullan",
|
||||
"blocked_service": "Engellenen hizmet",
|
||||
"block_all": "Hepsini engelle",
|
||||
"block_all": "Tümünü engelle",
|
||||
"unblock_all": "Tüm engellemeyi kaldır",
|
||||
"encryption_certificate_path": "Sertifika yolu",
|
||||
"encryption_private_key_path": "Özel anahtar yolu",
|
||||
@@ -507,7 +507,7 @@
|
||||
"interval_hours_plural": "{{count}} saat",
|
||||
"filters_configuration": "Filtre yapılandırması",
|
||||
"filters_enable": "Filtreleri etkinleştir",
|
||||
"filters_interval": "Filtreleri güncelleme sıklığı",
|
||||
"filters_interval": "Filtre güncelleme sıklığı",
|
||||
"disabled": "Devre dışı",
|
||||
"username_label": "Kullanıcı adı",
|
||||
"username_placeholder": "Kullanıcı adını girin",
|
||||
@@ -575,13 +575,13 @@
|
||||
"dnssec_enable_desc": "Giden DNS sorguları için DNSSEC özelliğini etkinleştir ve sonucu kontrol et (DNSSEC özellikli çözümleyici gerekli).",
|
||||
"validated_with_dnssec": "DNSSEC ile doğrulandı",
|
||||
"all_queries": "Tüm sorgular",
|
||||
"show_blocked_responses": "Engellenen",
|
||||
"show_blocked_responses": "Engellendi",
|
||||
"show_whitelisted_responses": "İzin verilen",
|
||||
"show_processed_responses": "İşlenen",
|
||||
"show_processed_responses": "İşlendi",
|
||||
"blocked_safebrowsing": "Güvenli gezinti tarafından engellendi",
|
||||
"blocked_adult_websites": "Yetişkin içerikli site engellendi",
|
||||
"blocked_threats": "Engellenen Tehditler",
|
||||
"allowed": "İzin verilen",
|
||||
"blocked_adult_websites": "Engellenen yetişkin içerikli siteler",
|
||||
"blocked_threats": "Engellenen tehditler",
|
||||
"allowed": "İzin verildi",
|
||||
"filtered": "Filtrelenen",
|
||||
"rewritten": "Yeniden yazılan",
|
||||
"safe_search": "Güvenli arama",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "53 numaralı bağlantı noktası genellikle \"DNSStubListener\" veya \"systemd-resolved\" hizmetleri tarafından kullanılır. Lütfen bu sorunun nasıl çözüleceğine ilişkin <0>bu talimatı</0> okuyun.",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home, bu istemciden gelen tüm DNS sorgularını yok sayar.",
|
||||
"client_not_in_allowed_clients": "\"İzin verilen istemciler\" listesinde olmadığı için istemciye izin verilmiyor.",
|
||||
"experimental": "Deneysel"
|
||||
"experimental": "Deneysel",
|
||||
"use_saved_key": "Önceden kaydedilmiş anahtarı kullan"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "你可以使用 <1>DNSCrypt</1> 的 <0>DNS Stamps</0> 或者 <2>DNS-over-HTTPS</2> 解析器",
|
||||
"example_upstream_tcp": "常规 DNS(基于 TCP )",
|
||||
"all_lists_up_to_date_toast": "所有列表都是最新的",
|
||||
"updated_upstream_dns_toast": "上游 DNS 已更新",
|
||||
"updated_upstream_dns_toast": "上游服务器保存成功",
|
||||
"dns_test_ok_toast": "指定的 DNS 服务器现已正常运行",
|
||||
"dns_test_not_ok_toast": "服务器 \"{{key}}\":无法使用,请检查你输入的是否正确",
|
||||
"unblock": "放行",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "加载中……",
|
||||
"page_table_footer_text": "页",
|
||||
"rows_table_footer_text": "行",
|
||||
"updated_custom_filtering_toast": "自定义过滤规则已更新",
|
||||
"updated_custom_filtering_toast": "自定义规则保存成功",
|
||||
"rule_removed_from_custom_filtering_toast": "规则已从自定义过滤规则列表中移除 {{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "规则已添加到自定义过滤规则列表中 {{rule}}",
|
||||
"query_log_response_status": "状态: {{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "53端口常被DNSStubListener或systemdn解析的服务占用。请阅读<0>这份关于如何解决这一问题的说明</0>",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home 会终止所有来自此客户端的DNS查询。",
|
||||
"client_not_in_allowed_clients": "此客户端不被允许,因为它不在“允许的客户端”列表中。",
|
||||
"experimental": "实验性的"
|
||||
"experimental": "实验性的",
|
||||
"use_saved_key": "使用之前保存的密钥"
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
"example_upstream_sdns": "您可使用關於 <1>DNSCrypt</1> 或 <2>DNS-over-HTTPS</2> 解析器之 <0>DNS 戳記</0>",
|
||||
"example_upstream_tcp": "一般的 DNS(透過 TCP)",
|
||||
"all_lists_up_to_date_toast": "所有的清單已是最新的",
|
||||
"updated_upstream_dns_toast": "已更新上游的 DNS 伺服器",
|
||||
"updated_upstream_dns_toast": "上游的伺服器被成功地儲存",
|
||||
"dns_test_ok_toast": "已明確指定的 DNS 伺服器正在正確地運作",
|
||||
"dns_test_not_ok_toast": "伺服器 \"{{key}}\":無法被使用,請檢查您已正確地填寫它",
|
||||
"unblock": "解除封鎖",
|
||||
@@ -235,7 +235,7 @@
|
||||
"loading_table_status": "正在載入…",
|
||||
"page_table_footer_text": "頁面",
|
||||
"rows_table_footer_text": "列",
|
||||
"updated_custom_filtering_toast": "已更新自訂的過濾規則",
|
||||
"updated_custom_filtering_toast": "自訂的規則被成功地儲存",
|
||||
"rule_removed_from_custom_filtering_toast": "從自訂的過濾規則中被移除的規則:{{rule}}",
|
||||
"rule_added_to_custom_filtering_toast": "被加至自訂的過濾規則中的規則:{{rule}}",
|
||||
"query_log_response_status": "狀態:{{value}}",
|
||||
@@ -613,5 +613,6 @@
|
||||
"port_53_faq_link": "連接埠 53 常被 \"DNSStubListener\" 或 \"systemd-resolved\" 服務佔用。請閱讀有關如何解決這個的<0>用法說明</0>。",
|
||||
"adg_will_drop_dns_queries": "AdGuard Home 將持續排除來自此用戶端之所有的 DNS 查詢。",
|
||||
"client_not_in_allowed_clients": "該用戶端未被允許,因為它不在\"已允許的用戶端\"清單中。",
|
||||
"experimental": "實驗性的"
|
||||
"experimental": "實驗性的",
|
||||
"use_saved_key": "使用該先前已儲存的金鑰"
|
||||
}
|
||||
|
||||
@@ -451,7 +451,6 @@ export const findActiveDhcp = (name) => async (dispatch, getState) => {
|
||||
dispatch(addErrorToast({ error: 'dhcp_static_ip_error' }));
|
||||
}
|
||||
|
||||
|
||||
if (isError) {
|
||||
dispatch(addErrorToast({ error: 'dhcp_error' }));
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ import CustomRules from '../../containers/CustomRules';
|
||||
import Services from '../Filters/Services';
|
||||
import Logs from '../Logs';
|
||||
|
||||
|
||||
const ROUTES = [
|
||||
{
|
||||
path: MENU_URLS.root,
|
||||
|
||||
@@ -17,7 +17,6 @@ const renderLink = ({ url, name }) => <a
|
||||
<strong>{name}</strong>
|
||||
</a>;
|
||||
|
||||
|
||||
const getTrackerInfo = (trackerData) => [{
|
||||
key: 'name_table_header',
|
||||
value: trackerData,
|
||||
|
||||
@@ -76,8 +76,8 @@ const Logs = () => {
|
||||
const filter = useSelector((state) => state.queryLogs.filter, shallowEqual);
|
||||
const logs = useSelector((state) => state.queryLogs.logs, shallowEqual);
|
||||
|
||||
const search = filter?.search || search_url_param || '';
|
||||
const response_status = filter?.response_status || response_status_url_param || '';
|
||||
const search = search_url_param || filter?.search || '';
|
||||
const response_status = response_status_url_param || filter?.response_status || '';
|
||||
|
||||
const [isSmallScreen, setIsSmallScreen] = useState(window.innerWidth < SMALL_SCREEN_SIZE);
|
||||
const [detailedDataCurrent, setDetailedDataCurrent] = useState({});
|
||||
|
||||
@@ -20,7 +20,6 @@ const renderInterfaces = (interfaces) => Object.keys(interfaces)
|
||||
return <option value={name} key={name}>{optionContent}</option>;
|
||||
});
|
||||
|
||||
|
||||
const getInterfaceValues = ({
|
||||
gateway_ip,
|
||||
hardware_address,
|
||||
|
||||
@@ -18,7 +18,7 @@ import i18n from '../../../i18n';
|
||||
import KeyStatus from './KeyStatus';
|
||||
import CertificateStatus from './CertificateStatus';
|
||||
import {
|
||||
DNS_OVER_QUIC_PORT, DNS_OVER_TLS_PORT, FORM_NAME, STANDARD_HTTPS_PORT,
|
||||
DNS_OVER_QUIC_PORT, DNS_OVER_TLS_PORT, FORM_NAME, STANDARD_HTTPS_PORT, ENCRYPTION_SOURCE,
|
||||
} from '../../../helpers/constants';
|
||||
|
||||
const validate = (values) => {
|
||||
@@ -46,6 +46,7 @@ const clearFields = (change, setTlsConfig, t) => {
|
||||
server_name: '',
|
||||
force_https: false,
|
||||
enabled: false,
|
||||
private_key_saved: false,
|
||||
};
|
||||
// eslint-disable-next-line no-alert
|
||||
if (window.confirm(t('encryption_reset'))) {
|
||||
@@ -83,6 +84,7 @@ let Form = (props) => {
|
||||
setTlsConfig,
|
||||
certificateSource,
|
||||
privateKeySource,
|
||||
privateKeySaved,
|
||||
} = props;
|
||||
|
||||
const isSavingDisabled = invalid
|
||||
@@ -265,7 +267,7 @@ let Form = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{certificateSource === 'content' && (
|
||||
{certificateSource === ENCRYPTION_SOURCE.CONTENT && (
|
||||
<Field
|
||||
id="certificate_chain"
|
||||
name="certificate_chain"
|
||||
@@ -277,7 +279,7 @@ let Form = (props) => {
|
||||
disabled={!isEnabled}
|
||||
/>
|
||||
)}
|
||||
{certificateSource === 'path' && (
|
||||
{certificateSource === ENCRYPTION_SOURCE.PATH && (
|
||||
<Field
|
||||
id="certificate_path"
|
||||
name="certificate_path"
|
||||
@@ -318,7 +320,7 @@ let Form = (props) => {
|
||||
component={renderRadioField}
|
||||
type="radio"
|
||||
className="form-control mr-2"
|
||||
value="path"
|
||||
value={ENCRYPTION_SOURCE.PATH}
|
||||
placeholder={t('encryption_key_source_path')}
|
||||
disabled={!isEnabled}
|
||||
/>
|
||||
@@ -327,28 +329,15 @@ let Form = (props) => {
|
||||
component={renderRadioField}
|
||||
type="radio"
|
||||
className="form-control mr-2"
|
||||
value="content"
|
||||
value={ENCRYPTION_SOURCE.CONTENT}
|
||||
placeholder={t('encryption_key_source_content')}
|
||||
disabled={!isEnabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{privateKeySource === 'content' && (
|
||||
{privateKeySource === ENCRYPTION_SOURCE.PATH && (
|
||||
<Field
|
||||
id="private_key"
|
||||
name="private_key"
|
||||
component="textarea"
|
||||
type="text"
|
||||
className="form-control form-control--textarea"
|
||||
placeholder={t('encryption_key_input')}
|
||||
onChange={handleChange}
|
||||
disabled={!isEnabled}
|
||||
/>
|
||||
)}
|
||||
{privateKeySource === 'path' && (
|
||||
<Field
|
||||
id="private_key_path"
|
||||
name="private_key_path"
|
||||
component={renderInputField}
|
||||
type="text"
|
||||
@@ -358,6 +347,36 @@ let Form = (props) => {
|
||||
disabled={!isEnabled}
|
||||
/>
|
||||
)}
|
||||
{privateKeySource === ENCRYPTION_SOURCE.CONTENT && [
|
||||
<Field
|
||||
key="private_key_saved"
|
||||
name="private_key_saved"
|
||||
type="checkbox"
|
||||
className="form__group form__group--settings mb-2"
|
||||
component={CheckboxField}
|
||||
disabled={!isEnabled}
|
||||
placeholder={t('use_saved_key')}
|
||||
onChange={(event) => {
|
||||
if (event.target.checked) {
|
||||
change('private_key', '');
|
||||
}
|
||||
if (handleChange) {
|
||||
handleChange(event);
|
||||
}
|
||||
}}
|
||||
/>,
|
||||
<Field
|
||||
id="private_key"
|
||||
key="private_key"
|
||||
name="private_key"
|
||||
component="textarea"
|
||||
type="text"
|
||||
className="form-control form-control--textarea"
|
||||
placeholder={t('encryption_key_input')}
|
||||
onChange={handleChange}
|
||||
disabled={!isEnabled || privateKeySaved}
|
||||
/>,
|
||||
]}
|
||||
</div>
|
||||
<div className="form__status">
|
||||
{(privateKey || privateKeyPath) && (
|
||||
@@ -422,6 +441,7 @@ Form.propTypes = {
|
||||
setTlsConfig: PropTypes.func.isRequired,
|
||||
certificateSource: PropTypes.string,
|
||||
privateKeySource: PropTypes.string,
|
||||
privateKeySaved: PropTypes.bool,
|
||||
};
|
||||
|
||||
const selector = formValueSelector(FORM_NAME.ENCRYPTION);
|
||||
@@ -434,6 +454,7 @@ Form = connect((state) => {
|
||||
const privateKeyPath = selector(state, 'private_key_path');
|
||||
const certificateSource = selector(state, 'certificate_source');
|
||||
const privateKeySource = selector(state, 'key_source');
|
||||
const privateKeySaved = selector(state, 'private_key_saved');
|
||||
return {
|
||||
isEnabled,
|
||||
certificateChain,
|
||||
@@ -442,6 +463,7 @@ Form = connect((state) => {
|
||||
privateKeyPath,
|
||||
certificateSource,
|
||||
privateKeySource,
|
||||
privateKeySaved,
|
||||
};
|
||||
})(Form);
|
||||
|
||||
|
||||
@@ -29,9 +29,13 @@ class Encryption extends Component {
|
||||
}, DEBOUNCE_TIMEOUT);
|
||||
|
||||
getInitialValues = (data) => {
|
||||
const { certificate_chain, private_key } = data;
|
||||
const certificate_source = certificate_chain ? 'content' : 'path';
|
||||
const key_source = private_key ? 'content' : 'path';
|
||||
const { certificate_chain, private_key, private_key_saved } = data;
|
||||
const certificate_source = certificate_chain
|
||||
? ENCRYPTION_SOURCE.CONTENT
|
||||
: ENCRYPTION_SOURCE.PATH;
|
||||
const key_source = private_key || private_key_saved
|
||||
? ENCRYPTION_SOURCE.CONTENT
|
||||
: ENCRYPTION_SOURCE.PATH;
|
||||
|
||||
return {
|
||||
...data,
|
||||
@@ -41,7 +45,9 @@ class Encryption extends Component {
|
||||
};
|
||||
|
||||
getSubmitValues = (values) => {
|
||||
const { certificate_source, key_source, ...config } = values;
|
||||
const {
|
||||
certificate_source, key_source, private_key_saved, ...config
|
||||
} = values;
|
||||
|
||||
if (certificate_source === ENCRYPTION_SOURCE.PATH) {
|
||||
config.certificate_chain = '';
|
||||
@@ -49,10 +55,15 @@ class Encryption extends Component {
|
||||
config.certificate_path = '';
|
||||
}
|
||||
|
||||
if (values.key_source === ENCRYPTION_SOURCE.PATH) {
|
||||
if (key_source === ENCRYPTION_SOURCE.PATH) {
|
||||
config.private_key = '';
|
||||
} else {
|
||||
config.private_key_path = '';
|
||||
|
||||
if (private_key_saved) {
|
||||
config.private_key = '';
|
||||
config.private_key_saved = private_key_saved;
|
||||
}
|
||||
}
|
||||
|
||||
return config;
|
||||
@@ -71,6 +82,7 @@ class Encryption extends Component {
|
||||
private_key,
|
||||
certificate_path,
|
||||
private_key_path,
|
||||
private_key_saved,
|
||||
} = encryption;
|
||||
|
||||
const initialValues = this.getInitialValues({
|
||||
@@ -84,6 +96,7 @@ class Encryption extends Component {
|
||||
private_key,
|
||||
certificate_path,
|
||||
private_key_path,
|
||||
private_key_saved,
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,14 +4,12 @@ import { Field, reduxForm } from 'redux-form';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import flow from 'lodash/flow';
|
||||
|
||||
import { renderRadioField, toNumber } from '../../../helpers/form';
|
||||
import { FORM_NAME, STATS_INTERVALS_DAYS } from '../../../helpers/constants';
|
||||
import { renderRadioField, toNumber, CheckboxField } from '../../../helpers/form';
|
||||
import { FORM_NAME, STATS_INTERVALS_DAYS, DISABLED_STATS_INTERVAL } from '../../../helpers/constants';
|
||||
import '../FormButton.css';
|
||||
|
||||
const getIntervalTitle = (interval, t) => {
|
||||
switch (interval) {
|
||||
case 0:
|
||||
return t('disabled');
|
||||
case 1:
|
||||
return t('interval_24_hour');
|
||||
default:
|
||||
@@ -19,24 +17,36 @@ const getIntervalTitle = (interval, t) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getIntervalFields = (processing, t, toNumber) => STATS_INTERVALS_DAYS.map((interval) => <Field
|
||||
key={interval}
|
||||
name="interval"
|
||||
type="radio"
|
||||
component={renderRadioField}
|
||||
value={interval}
|
||||
placeholder={getIntervalTitle(interval, t)}
|
||||
normalize={toNumber}
|
||||
disabled={processing}
|
||||
/>);
|
||||
|
||||
const Form = (props) => {
|
||||
const {
|
||||
handleSubmit, processing, submitting, invalid, handleReset, processingReset, t,
|
||||
handleSubmit,
|
||||
change,
|
||||
processing,
|
||||
submitting,
|
||||
invalid,
|
||||
handleReset,
|
||||
processingReset,
|
||||
t,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="form__group form__group--settings">
|
||||
<Field
|
||||
name="enabled"
|
||||
type="checkbox"
|
||||
component={CheckboxField}
|
||||
placeholder={t('statistics_enable')}
|
||||
disabled={processing}
|
||||
onChange={(event) => {
|
||||
if (event.target.checked) {
|
||||
change('interval', STATS_INTERVALS_DAYS[0]);
|
||||
} else {
|
||||
change('interval', DISABLED_STATS_INTERVAL);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<label className="form__label form__label--with-desc">
|
||||
<Trans>statistics_retention</Trans>
|
||||
</label>
|
||||
@@ -45,7 +55,23 @@ const Form = (props) => {
|
||||
</div>
|
||||
<div className="form__group form__group--settings mt-2">
|
||||
<div className="custom-controls-stacked">
|
||||
{getIntervalFields(processing, t, toNumber)}
|
||||
{STATS_INTERVALS_DAYS.map((interval) => (
|
||||
<Field
|
||||
key={interval}
|
||||
name="interval"
|
||||
type="radio"
|
||||
component={renderRadioField}
|
||||
value={interval}
|
||||
placeholder={getIntervalTitle(interval, t)}
|
||||
normalize={toNumber}
|
||||
disabled={processing}
|
||||
onChange={(event) => {
|
||||
if (event.target.checked) {
|
||||
change('enabled', true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
|
||||
@@ -8,13 +8,14 @@ import Form from './Form';
|
||||
class StatsConfig extends Component {
|
||||
handleFormSubmit = (values) => {
|
||||
const { t, interval: prevInterval } = this.props;
|
||||
const config = { interval: values.interval };
|
||||
|
||||
if (values.interval < prevInterval) {
|
||||
if (config.interval < prevInterval) {
|
||||
if (window.confirm(t('statistics_retention_confirm'))) {
|
||||
this.props.setStatsConfig(values);
|
||||
this.props.setStatsConfig(config);
|
||||
}
|
||||
} else {
|
||||
this.props.setStatsConfig(values);
|
||||
this.props.setStatsConfig(config);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -39,7 +40,10 @@ class StatsConfig extends Component {
|
||||
>
|
||||
<div className="form">
|
||||
<Form
|
||||
initialValues={{ interval }}
|
||||
initialValues={{
|
||||
interval,
|
||||
enabled: !!interval,
|
||||
}}
|
||||
onSubmit={this.handleFormSubmit}
|
||||
processing={processing}
|
||||
processingReset={processingReset}
|
||||
|
||||
@@ -355,7 +355,8 @@ export const ENCRYPTION_SOURCE = {
|
||||
export const FILTERED = 'Filtered';
|
||||
export const NOT_FILTERED = 'NotFiltered';
|
||||
|
||||
export const STATS_INTERVALS_DAYS = [0, 1, 7, 30, 90];
|
||||
export const DISABLED_STATS_INTERVAL = 0;
|
||||
export const STATS_INTERVALS_DAYS = [1, 7, 30, 90];
|
||||
|
||||
export const QUERY_LOG_INTERVALS_DAYS = [0.25, 1, 7, 30, 90];
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import twosky from 'MainRoot/.twosky.json';
|
||||
|
||||
export const {
|
||||
|
||||
@@ -47,7 +47,6 @@ Submit = connect((state) => {
|
||||
};
|
||||
})(Submit);
|
||||
|
||||
|
||||
export default flow([
|
||||
withTranslation(),
|
||||
reduxForm({
|
||||
|
||||
8
go.mod
8
go.mod
@@ -3,8 +3,8 @@ module github.com/AdguardTeam/AdGuardHome
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/AdguardTeam/dnsproxy v0.39.2
|
||||
github.com/AdguardTeam/golibs v0.9.1
|
||||
github.com/AdguardTeam/dnsproxy v0.39.4
|
||||
github.com/AdguardTeam/golibs v0.9.2
|
||||
github.com/AdguardTeam/urlfilter v0.14.6
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/ameshkov/dnscrypt/v2 v2.2.1
|
||||
@@ -23,10 +23,10 @@ require (
|
||||
github.com/stretchr/objx v0.1.1 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/ti-mo/netfilter v0.4.0
|
||||
go.etcd.io/bbolt v1.3.5
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
howett.net/plist v0.0.0-20201203080718-1454fab16a06
|
||||
|
||||
19
go.sum
19
go.sum
@@ -9,13 +9,12 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D
|
||||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
|
||||
github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf h1:gc042VRSIRSUzZ+Px6xQCRWNJZTaPkomisDfUZmoFNk=
|
||||
github.com/AdguardTeam/dhcp v0.0.0-20210519141215-51808c73c0bf/go.mod h1:TKl4jN3Voofo4UJIicyNhWGp/nlQqQkFxmwIFTvBkKI=
|
||||
github.com/AdguardTeam/dnsproxy v0.39.2 h1:GqsR1S4fFfVsVCSrdrfa0RfsQ2u+MeNUMqDkxdTD3gU=
|
||||
github.com/AdguardTeam/dnsproxy v0.39.2/go.mod h1:aNXKNdTyKfgAG2OS712SYSaGIM9AasZsZxfiY4YiR/0=
|
||||
github.com/AdguardTeam/dnsproxy v0.39.4 h1:vjcogr0qpSTvRYzbXabBXblfzYpx+LOn91kjtnYgcrU=
|
||||
github.com/AdguardTeam/dnsproxy v0.39.4/go.mod h1:JZUxXM70BUlAmMaJEPa6Wh+Tz7eBAQx6DM1GMt+Ff5E=
|
||||
github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||
github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||
github.com/AdguardTeam/golibs v0.8.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4=
|
||||
github.com/AdguardTeam/golibs v0.9.1 h1:mHSN4LfaY1uGmHPsl97paAND/VeSnM5r9XQ7pSYx93o=
|
||||
github.com/AdguardTeam/golibs v0.9.1/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY=
|
||||
github.com/AdguardTeam/golibs v0.9.2 h1:H3BDFkaosxvb+UgFlNVyN66GZ+JglcZULnJ7z7PukyQ=
|
||||
github.com/AdguardTeam/golibs v0.9.2/go.mod h1:fCAMwPBJ8S7YMYbTWvYS+eeTLblP5E04IDtNAo7y7IY=
|
||||
github.com/AdguardTeam/gomitmproxy v0.2.0/go.mod h1:Qdv0Mktnzer5zpdpi5rAwixNJzW2FN91LjKJCkVbYGU=
|
||||
github.com/AdguardTeam/urlfilter v0.14.6 h1:emqoKZElooHACYehRBYENeKVN1a/rspxiqTIMYLuoIo=
|
||||
github.com/AdguardTeam/urlfilter v0.14.6/go.mod h1:klx4JbOfc4EaNb5lWLqOwfg+pVcyRukmoJRvO55lL5U=
|
||||
@@ -250,8 +249,8 @@ github.com/u-root/u-root v7.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/R
|
||||
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
|
||||
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
|
||||
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
|
||||
@@ -337,6 +336,7 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -354,15 +354,14 @@ golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
||||
@@ -13,8 +13,6 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghio"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
@@ -115,12 +113,6 @@ func (sr *systemResolvers) getAddrs() (addrs []string, err error) {
|
||||
return nil, fmt.Errorf("getting the command's stdout pipe: %w", err)
|
||||
}
|
||||
|
||||
var stdoutLimited io.Reader
|
||||
stdoutLimited, err = aghio.LimitReader(stdout, aghos.MaxCmdOutputSize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("limiting stdout reader: %w", err)
|
||||
}
|
||||
|
||||
go writeExit(stdin)
|
||||
|
||||
err = cmd.Start()
|
||||
@@ -128,7 +120,7 @@ func (sr *systemResolvers) getAddrs() (addrs []string, err error) {
|
||||
return nil, fmt.Errorf("start command executing: %w", err)
|
||||
}
|
||||
|
||||
s := bufio.NewScanner(stdoutLimited)
|
||||
s := bufio.NewScanner(stdout)
|
||||
addrs = scanAddrs(s)
|
||||
|
||||
err = cmd.Wait()
|
||||
|
||||
@@ -4,10 +4,17 @@
|
||||
package aghos
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"path"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
|
||||
// UnsupportedError is returned by functions and methods when a particular
|
||||
@@ -43,11 +50,6 @@ func HaveAdminRights() (bool, error) {
|
||||
return haveAdminRights()
|
||||
}
|
||||
|
||||
// SendProcessSignal sends signal to a process.
|
||||
func SendProcessSignal(pid int, sig syscall.Signal) error {
|
||||
return sendProcessSignal(pid, sig)
|
||||
}
|
||||
|
||||
// MaxCmdOutputSize is the maximum length of performed shell command output.
|
||||
const MaxCmdOutputSize = 2 * 1024
|
||||
|
||||
@@ -58,13 +60,101 @@ func RunCommand(command string, arguments ...string) (int, string, error) {
|
||||
if len(out) > MaxCmdOutputSize {
|
||||
out = out[:MaxCmdOutputSize]
|
||||
}
|
||||
if err != nil {
|
||||
return 1, "", fmt.Errorf("exec.Command(%s) failed: %v: %s", command, err, string(out))
|
||||
|
||||
if errors.As(err, new(*exec.ExitError)) {
|
||||
return cmd.ProcessState.ExitCode(), string(out), nil
|
||||
} else if err != nil {
|
||||
return 1, "", fmt.Errorf("exec.Command(%s) failed: %w: %s", command, err, string(out))
|
||||
}
|
||||
|
||||
return cmd.ProcessState.ExitCode(), string(out), nil
|
||||
}
|
||||
|
||||
// PIDByCommand searches for process named command and returns its PID ignoring
|
||||
// the PIDs from except. If no processes found, the error returned.
|
||||
func PIDByCommand(command string, except ...int) (pid int, err error) {
|
||||
// Don't use -C flag here since it's a feature of linux's ps
|
||||
// implementation. Use POSIX-compatible flags instead.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/3457.
|
||||
cmd := exec.Command("ps", "-A", "-o", "pid=", "-o", "comm=")
|
||||
|
||||
var stdout io.ReadCloser
|
||||
if stdout, err = cmd.StdoutPipe(); err != nil {
|
||||
return 0, fmt.Errorf("getting the command's stdout pipe: %w", err)
|
||||
}
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
return 0, fmt.Errorf("start command executing: %w", err)
|
||||
}
|
||||
|
||||
var instNum int
|
||||
pid, instNum, err = parsePSOutput(stdout, command, except...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
return 0, fmt.Errorf("executing the command: %w", err)
|
||||
}
|
||||
|
||||
switch instNum {
|
||||
case 0:
|
||||
// TODO(e.burkov): Use constant error.
|
||||
return 0, fmt.Errorf("no %s instances found", command)
|
||||
case 1:
|
||||
// Go on.
|
||||
default:
|
||||
log.Info("warning: %d %s instances found", instNum, command)
|
||||
}
|
||||
|
||||
if code := cmd.ProcessState.ExitCode(); code != 0 {
|
||||
return 0, fmt.Errorf("ps finished with code %d", code)
|
||||
}
|
||||
|
||||
return pid, nil
|
||||
}
|
||||
|
||||
// parsePSOutput scans the output of ps searching the largest PID of the process
|
||||
// associated with cmdName ignoring PIDs from ignore. Valid r's line shoud be
|
||||
// like:
|
||||
//
|
||||
// 123 ./example-cmd
|
||||
// 1230 some/base/path/example-cmd
|
||||
// 3210 example-cmd
|
||||
//
|
||||
func parsePSOutput(r io.Reader, cmdName string, ignore ...int) (largest, instNum int, err error) {
|
||||
s := bufio.NewScanner(r)
|
||||
ScanLoop:
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
if len(fields) != 2 || path.Base(fields[1]) != cmdName {
|
||||
continue
|
||||
}
|
||||
|
||||
cur, aerr := strconv.Atoi(fields[0])
|
||||
if aerr != nil || cur < 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, pid := range ignore {
|
||||
if cur == pid {
|
||||
continue ScanLoop
|
||||
}
|
||||
}
|
||||
|
||||
instNum++
|
||||
if cur > largest {
|
||||
largest = cur
|
||||
}
|
||||
}
|
||||
if err = s.Err(); err != nil {
|
||||
return 0, 0, fmt.Errorf("scanning stdout: %w", err)
|
||||
}
|
||||
|
||||
return largest, instNum, nil
|
||||
}
|
||||
|
||||
// IsOpenWrt returns true if host OS is OpenWrt.
|
||||
func IsOpenWrt() (ok bool) {
|
||||
return isOpenWrt()
|
||||
|
||||
@@ -20,10 +20,6 @@ func haveAdminRights() (bool, error) {
|
||||
return os.Getuid() == 0, nil
|
||||
}
|
||||
|
||||
func sendProcessSignal(pid int, sig syscall.Signal) error {
|
||||
return syscall.Kill(pid, sig)
|
||||
}
|
||||
|
||||
func isOpenWrt() (ok bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -20,10 +20,6 @@ func haveAdminRights() (bool, error) {
|
||||
return os.Getuid() == 0, nil
|
||||
}
|
||||
|
||||
func sendProcessSignal(pid int, sig syscall.Signal) error {
|
||||
return syscall.Kill(pid, sig)
|
||||
}
|
||||
|
||||
func isOpenWrt() (ok bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -25,10 +25,6 @@ func haveAdminRights() (bool, error) {
|
||||
return os.Getuid() == 0, nil
|
||||
}
|
||||
|
||||
func sendProcessSignal(pid int, sig syscall.Signal) error {
|
||||
return syscall.Kill(pid, sig)
|
||||
}
|
||||
|
||||
func isOpenWrt() (ok bool) {
|
||||
var err error
|
||||
ok, err = FileWalker(func(r io.Reader) (_ []string, cont bool, err error) {
|
||||
|
||||
98
internal/aghos/os_test.go
Normal file
98
internal/aghos/os_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package aghos
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghio"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestLargestLabeled(t *testing.T) {
|
||||
const (
|
||||
comm = `command-name`
|
||||
nl = "\n"
|
||||
)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
data []byte
|
||||
wantPID int
|
||||
wantInstNum int
|
||||
}{{
|
||||
name: "success",
|
||||
data: []byte(nl +
|
||||
` 123 not-a-` + comm + nl +
|
||||
` 321 ` + comm + nl,
|
||||
),
|
||||
wantPID: 321,
|
||||
wantInstNum: 1,
|
||||
}, {
|
||||
name: "several",
|
||||
data: []byte(nl +
|
||||
`1 ` + comm + nl +
|
||||
`5 /` + comm + nl +
|
||||
`2 /some/path/` + comm + nl +
|
||||
`4 ./` + comm + nl +
|
||||
`3 ` + comm + nl +
|
||||
`10 .` + comm + nl,
|
||||
),
|
||||
wantPID: 5,
|
||||
wantInstNum: 5,
|
||||
}, {
|
||||
name: "no_any",
|
||||
data: []byte(nl +
|
||||
`1 ` + `not-a-` + comm + nl +
|
||||
`2 ` + `not-a-` + comm + nl +
|
||||
`3 ` + `not-a-` + comm + nl,
|
||||
),
|
||||
wantPID: 0,
|
||||
wantInstNum: 0,
|
||||
}, {
|
||||
name: "weird_input",
|
||||
data: []byte(nl +
|
||||
`abc ` + comm + nl +
|
||||
`-1 ` + comm + nl,
|
||||
),
|
||||
wantPID: 0,
|
||||
wantInstNum: 0,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
r := bytes.NewReader(tc.data)
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
pid, instNum, err := parsePSOutput(r, comm)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tc.wantPID, pid)
|
||||
assert.Equal(t, tc.wantInstNum, instNum)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("scanner_fail", func(t *testing.T) {
|
||||
lr, err := aghio.LimitReader(bytes.NewReader([]byte{1, 2, 3}), 0)
|
||||
require.NoError(t, err)
|
||||
|
||||
target := &aghio.LimitReachedError{}
|
||||
_, _, err = parsePSOutput(lr, "")
|
||||
require.ErrorAs(t, err, &target)
|
||||
|
||||
assert.EqualValues(t, 0, target.Limit)
|
||||
})
|
||||
|
||||
t.Run("ignore", func(t *testing.T) {
|
||||
r := bytes.NewReader([]byte(nl +
|
||||
`1 ` + comm + nl +
|
||||
`2 ` + comm + nl +
|
||||
`3` + comm + nl,
|
||||
))
|
||||
|
||||
pid, instances, err := parsePSOutput(r, comm, 1, 3)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 2, pid)
|
||||
assert.Equal(t, 1, instances)
|
||||
})
|
||||
}
|
||||
@@ -4,8 +4,6 @@
|
||||
package aghos
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
@@ -34,10 +32,6 @@ func haveAdminRights() (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func sendProcessSignal(pid int, sig syscall.Signal) error {
|
||||
return Unsupported("kill")
|
||||
}
|
||||
|
||||
func isOpenWrt() (ok bool) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
package home
|
||||
// Package aghtime defines some types for convenient work with time values.
|
||||
package aghtime
|
||||
|
||||
import (
|
||||
"time"
|
||||
@@ -23,22 +24,30 @@ type Duration struct {
|
||||
//
|
||||
func (d Duration) String() (str string) {
|
||||
str = d.Duration.String()
|
||||
secs := d.Seconds()
|
||||
var secsInt int
|
||||
if secsInt = int(secs); float64(secsInt) != secs || secsInt%60 != 0 {
|
||||
return str
|
||||
}
|
||||
|
||||
const (
|
||||
tailMin = len(`0s`)
|
||||
tailMinSec = len(`0m0s`)
|
||||
|
||||
secsInHour = time.Hour / time.Second
|
||||
minsInHour = time.Hour / time.Minute
|
||||
)
|
||||
|
||||
if (secsInt%3600)/60 != 0 {
|
||||
return str[:len(str)-tailMin]
|
||||
}
|
||||
switch rounded := d.Duration / time.Second; {
|
||||
case
|
||||
rounded == 0,
|
||||
rounded*time.Second != d.Duration,
|
||||
rounded%60 != 0:
|
||||
// Return the uncutted value if it's either equal to zero or has
|
||||
// fractions of a second or even whole seconds in it.
|
||||
return str
|
||||
|
||||
return str[:len(str)-tailMinSec]
|
||||
case (rounded%secsInHour)/minsInHour != 0:
|
||||
return str[:len(str)-tailMin]
|
||||
|
||||
default:
|
||||
return str[:len(str)-tailMinSec]
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface for Duration.
|
||||
@@ -1,4 +1,4 @@
|
||||
package home
|
||||
package aghtime
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -46,6 +46,9 @@ func TestDuration_String(t *testing.T) {
|
||||
}, {
|
||||
name: "1m1.001s",
|
||||
val: time.Minute + time.Second + time.Millisecond,
|
||||
}, {
|
||||
name: "0s",
|
||||
val: 0,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtime"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||
"github.com/AdguardTeam/dnsproxy/proxy"
|
||||
"github.com/AdguardTeam/dnsproxy/upstream"
|
||||
@@ -87,6 +88,9 @@ type FilteringConfig struct {
|
||||
BootstrapDNS []string `yaml:"bootstrap_dns"` // a list of bootstrap DNS for DoH and DoT (plain DNS only)
|
||||
AllServers bool `yaml:"all_servers"` // if true, parallel queries to all configured upstream servers are enabled
|
||||
FastestAddr bool `yaml:"fastest_addr"` // use Fastest Address algorithm
|
||||
// FastestTimeout replaces the default timeout for dialing IP addresses
|
||||
// when FastestAddr is true.
|
||||
FastestTimeout aghtime.Duration `yaml:"fastest_timeout"`
|
||||
|
||||
// Access settings
|
||||
// --
|
||||
@@ -236,6 +240,7 @@ func (s *Server) createProxyConfig() (proxy.Config, error) {
|
||||
proxyConfig.UpstreamMode = proxy.UModeParallel
|
||||
} else if s.conf.FastestAddr {
|
||||
proxyConfig.UpstreamMode = proxy.UModeFastestAddr
|
||||
proxyConfig.FastestPingTimeout = s.conf.FastestTimeout.Duration
|
||||
}
|
||||
|
||||
if len(s.conf.BogusNXDomain) > 0 {
|
||||
|
||||
@@ -31,6 +31,7 @@ var serviceRulesArray = []svc{
|
||||
"||messenger.com^",
|
||||
"||facebookcorewwwi.onion^",
|
||||
"||fbcdn.com^",
|
||||
"||fb.watch^",
|
||||
}},
|
||||
{"twitter", []string{"||twitter.com^", "||twttr.com^", "||t.co^", "||twimg.com^"}},
|
||||
{"youtube", []string{
|
||||
@@ -206,6 +207,8 @@ var serviceRulesArray = []svc{
|
||||
{"disneyplus", []string{
|
||||
"||disney-plus.net^",
|
||||
"||disneyplus.com^",
|
||||
"||disney.playback.edge.bamgrid.com^",
|
||||
"||media.dssott.com^",
|
||||
}},
|
||||
{"hulu", []string{
|
||||
"||hulu.com^",
|
||||
|
||||
@@ -8,12 +8,14 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtime"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/querylog"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/stats"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||
"github.com/AdguardTeam/dnsproxy/fastip"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/google/renameio/maybe"
|
||||
@@ -106,9 +108,9 @@ type dnsConfig struct {
|
||||
QueryLogEnabled bool `yaml:"querylog_enabled"` // if true, query log is enabled
|
||||
QueryLogFileEnabled bool `yaml:"querylog_file_enabled"` // if true, query log will be written to a file
|
||||
// QueryLogInterval is the interval for query log's files rotation.
|
||||
QueryLogInterval Duration `yaml:"querylog_interval"`
|
||||
QueryLogMemSize uint32 `yaml:"querylog_size_memory"` // number of entries kept in memory before they are flushed to disk
|
||||
AnonymizeClientIP bool `yaml:"anonymize_client_ip"` // anonymize clients' IP addresses in logs and stats
|
||||
QueryLogInterval aghtime.Duration `yaml:"querylog_interval"`
|
||||
QueryLogMemSize uint32 `yaml:"querylog_size_memory"` // number of entries kept in memory before they are flushed to disk
|
||||
AnonymizeClientIP bool `yaml:"anonymize_client_ip"` // anonymize clients' IP addresses in logs and stats
|
||||
|
||||
dnsforward.FilteringConfig `yaml:",inline"`
|
||||
|
||||
@@ -117,7 +119,7 @@ type dnsConfig struct {
|
||||
DnsfilterConf filtering.Config `yaml:",inline"`
|
||||
|
||||
// UpstreamTimeout is the timeout for querying upstream servers.
|
||||
UpstreamTimeout Duration `yaml:"upstream_timeout"`
|
||||
UpstreamTimeout aghtime.Duration `yaml:"upstream_timeout"`
|
||||
|
||||
// LocalDomainName is the domain name used for known internal hosts.
|
||||
// For example, a machine called "myhost" can be addressed as
|
||||
@@ -178,6 +180,9 @@ var config = configuration{
|
||||
Ratelimit: 20,
|
||||
RefuseAny: true,
|
||||
AllServers: false,
|
||||
FastestTimeout: aghtime.Duration{
|
||||
Duration: fastip.DefaultPingWaitTimeout,
|
||||
},
|
||||
|
||||
TrustedProxies: []string{"127.0.0.0/8", "::1/128"},
|
||||
|
||||
@@ -189,7 +194,7 @@ var config = configuration{
|
||||
},
|
||||
FilteringEnabled: true, // whether or not use filter lists
|
||||
FiltersUpdateIntervalHours: 24,
|
||||
UpstreamTimeout: Duration{Duration: dnsforward.DefaultTimeout},
|
||||
UpstreamTimeout: aghtime.Duration{Duration: dnsforward.DefaultTimeout},
|
||||
LocalDomainName: "lan",
|
||||
ResolveClients: true,
|
||||
UsePrivateRDNS: true,
|
||||
@@ -216,7 +221,7 @@ func initConfig() {
|
||||
|
||||
config.DNS.QueryLogEnabled = true
|
||||
config.DNS.QueryLogFileEnabled = true
|
||||
config.DNS.QueryLogInterval = Duration{Duration: 90 * 24 * time.Hour}
|
||||
config.DNS.QueryLogInterval = aghtime.Duration{Duration: 90 * 24 * time.Hour}
|
||||
config.DNS.QueryLogMemSize = 1000
|
||||
|
||||
config.DNS.CacheSize = 4 * 1024 * 1024
|
||||
@@ -285,7 +290,7 @@ func parseConfig() error {
|
||||
}
|
||||
|
||||
if config.DNS.UpstreamTimeout.Duration == 0 {
|
||||
config.DNS.UpstreamTimeout = Duration{Duration: dnsforward.DefaultTimeout}
|
||||
config.DNS.UpstreamTimeout = aghtime.Duration{Duration: dnsforward.DefaultTimeout}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -332,7 +337,7 @@ func (c *configuration) write() error {
|
||||
Context.queryLog.WriteDiskConfig(&dc)
|
||||
config.DNS.QueryLogEnabled = dc.Enabled
|
||||
config.DNS.QueryLogFileEnabled = dc.FileEnabled
|
||||
config.DNS.QueryLogInterval = Duration{Duration: dc.RotationIvl}
|
||||
config.DNS.QueryLogInterval = aghtime.Duration{Duration: dc.RotationIvl}
|
||||
config.DNS.QueryLogMemSize = dc.MemSize
|
||||
config.DNS.AnonymizeClientIP = dc.AnonymizeClientIP
|
||||
}
|
||||
|
||||
@@ -116,13 +116,6 @@ func Main(clientBuildFS fs.FS) {
|
||||
}()
|
||||
|
||||
if args.serviceControlAction != "" {
|
||||
// TODO(a.garipov): github.com/kardianos/service doesn't seem to
|
||||
// support OpenBSD currently. Either patch it to do so or make
|
||||
// our own implementation of the service.System interface.
|
||||
if runtime.GOOS == "openbsd" {
|
||||
log.Fatal("service actions are not supported on openbsd, see issue 3226")
|
||||
}
|
||||
|
||||
handleServiceControlAction(args, clientBuildFS)
|
||||
|
||||
return
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/kardianos/service"
|
||||
@@ -26,33 +28,37 @@ const (
|
||||
serviceDescription = "AdGuard Home: Network-level blocker"
|
||||
)
|
||||
|
||||
// Represents the program that will be launched by a service or daemon
|
||||
// program represents the program that will be launched by as a service or a
|
||||
// daemon.
|
||||
type program struct {
|
||||
clientBuildFS fs.FS
|
||||
opts options
|
||||
}
|
||||
|
||||
// Start should quickly start the program
|
||||
func (p *program) Start(s service.Service) error {
|
||||
// Start should not block. Do the actual work async.
|
||||
// Start implements service.Interface interface for *program.
|
||||
func (p *program) Start(_ service.Service) (err error) {
|
||||
// Start should not block. Do the actual work async.
|
||||
args := p.opts
|
||||
args.runningAsService = true
|
||||
|
||||
go run(args, p.clientBuildFS)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop stops the program
|
||||
func (p *program) Stop(s service.Service) error {
|
||||
// Stop should not block. Return with a few seconds.
|
||||
// Stop implements service.Interface interface for *program.
|
||||
func (p *program) Stop(_ service.Service) error {
|
||||
// Stop should not block. Return with a few seconds.
|
||||
if Context.appSignalChannel == nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
Context.appSignalChannel <- syscall.SIGINT
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// svcStatus check the service's status.
|
||||
// svcStatus returns the service's status.
|
||||
//
|
||||
// On OpenWrt, the service utility may not exist. We use our service script
|
||||
// directly in this case.
|
||||
@@ -87,8 +93,8 @@ func svcAction(s service.Service, action string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
// Send SIGHUP to a process with ID taken from our pid-file
|
||||
// If pid-file doesn't exist, find our PID using 'ps' command
|
||||
// Send SIGHUP to a process with PID taken from our .pid file. If it doesn't
|
||||
// exist, find our PID using 'ps' command.
|
||||
func sendSigReload() {
|
||||
if runtime.GOOS == "windows" {
|
||||
log.Error("not implemented on windows")
|
||||
@@ -97,41 +103,48 @@ func sendSigReload() {
|
||||
}
|
||||
|
||||
pidfile := fmt.Sprintf("/var/run/%s.pid", serviceName)
|
||||
var pid int
|
||||
data, err := os.ReadFile(pidfile)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
var code int
|
||||
var psdata string
|
||||
code, psdata, err = aghos.RunCommand("ps", "-C", serviceName, "-o", "pid=")
|
||||
if err != nil || code != 0 {
|
||||
log.Error("finding AdGuardHome process: code: %d, error: %s", code, err)
|
||||
if pid, err = aghos.PIDByCommand(serviceName, os.Getpid()); err != nil {
|
||||
log.Error("finding AdGuardHome process: %s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
data = []byte(psdata)
|
||||
} else if err != nil {
|
||||
log.Error("reading pid file %s: %s", pidfile, err)
|
||||
|
||||
return
|
||||
|
||||
} else {
|
||||
parts := strings.SplitN(string(data), "\n", 2)
|
||||
if len(parts) == 0 {
|
||||
log.Error("can't read pid file %s: bad value", pidfile)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if pid, err = strconv.Atoi(strings.TrimSpace(parts[0])); err != nil {
|
||||
log.Error("can't read pid file %s: %s", pidfile, err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
parts := strings.SplitN(string(data), "\n", 2)
|
||||
if len(parts) == 0 {
|
||||
log.Error("Can't read PID file %s: bad value", pidfile)
|
||||
var proc *os.Process
|
||||
if proc, err = os.FindProcess(pid); err != nil {
|
||||
log.Error("can't send signal to pid %d: %s", pid, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(strings.TrimSpace(parts[0]))
|
||||
if err != nil {
|
||||
log.Error("Can't read PID file %s: %s", pidfile, err)
|
||||
if err = proc.Signal(syscall.SIGHUP); err != nil {
|
||||
log.Error("Can't send signal to pid %d: %s", pid, err)
|
||||
|
||||
return
|
||||
}
|
||||
err = aghos.SendProcessSignal(pid, syscall.SIGHUP)
|
||||
if err != nil {
|
||||
log.Error("Can't send signal to PID %d: %s", pid, err)
|
||||
return
|
||||
}
|
||||
log.Debug("Sent signal to PID %d", pid)
|
||||
|
||||
log.Debug("sent signal to PID %d", pid)
|
||||
}
|
||||
|
||||
// handleServiceControlAction one of the possible control actions:
|
||||
@@ -145,11 +158,16 @@ func sendSigReload() {
|
||||
// it is specified when we register a service, and it indicates to the app
|
||||
// that it is being run as a service/daemon.
|
||||
func handleServiceControlAction(opts options, clientBuildFS fs.FS) {
|
||||
// Call chooseSystem expicitly to introduce OpenBSD support for service
|
||||
// package. It's a noop for other GOOS values.
|
||||
chooseSystem()
|
||||
|
||||
action := opts.serviceControlAction
|
||||
log.Printf("Service control action: %s", action)
|
||||
|
||||
if action == "reload" {
|
||||
sendSigReload()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -157,6 +175,7 @@ func handleServiceControlAction(opts options, clientBuildFS fs.FS) {
|
||||
if err != nil {
|
||||
log.Fatal("Unable to find the path to the current directory")
|
||||
}
|
||||
|
||||
runOpts := opts
|
||||
runOpts.serviceControlAction = "run"
|
||||
svcConfig := &service.Config{
|
||||
@@ -167,39 +186,39 @@ func handleServiceControlAction(opts options, clientBuildFS fs.FS) {
|
||||
Arguments: serialize(runOpts),
|
||||
}
|
||||
configureService(svcConfig)
|
||||
|
||||
prg := &program{
|
||||
clientBuildFS: clientBuildFS,
|
||||
opts: runOpts,
|
||||
}
|
||||
s, err := service.New(prg, svcConfig)
|
||||
if err != nil {
|
||||
var s service.Service
|
||||
if s, err = service.New(prg, svcConfig); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if action == "status" {
|
||||
switch action {
|
||||
case "status":
|
||||
handleServiceStatusCommand(s)
|
||||
} else if action == "run" {
|
||||
err = s.Run()
|
||||
if err != nil {
|
||||
case "run":
|
||||
if err = s.Run(); err != nil {
|
||||
log.Fatalf("Failed to run service: %s", err)
|
||||
}
|
||||
} else if action == "install" {
|
||||
case "install":
|
||||
initConfigFilename(opts)
|
||||
initWorkingDir(opts)
|
||||
handleServiceInstallCommand(s)
|
||||
} else if action == "uninstall" {
|
||||
case "uninstall":
|
||||
handleServiceUninstallCommand(s)
|
||||
} else {
|
||||
err = svcAction(s, action)
|
||||
if err != nil {
|
||||
default:
|
||||
if err = svcAction(s, action); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Action %s has been done successfully on %s", action, service.ChosenSystem().String())
|
||||
log.Printf("action %s has been done successfully on %s", action, service.ChosenSystem())
|
||||
}
|
||||
|
||||
// handleServiceStatusCommand handles service "status" command
|
||||
// handleServiceStatusCommand handles service "status" command.
|
||||
func handleServiceStatusCommand(s service.Service) {
|
||||
status, errSt := svcStatus(s)
|
||||
if errSt != nil {
|
||||
@@ -224,15 +243,16 @@ func handleServiceInstallCommand(s service.Service) {
|
||||
}
|
||||
|
||||
if aghos.IsOpenWrt() {
|
||||
// On OpenWrt it is important to run enable after the service installation
|
||||
// Otherwise, the service won't start on the system startup
|
||||
// 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
|
||||
// Start automatically after install.
|
||||
err = svcAction(s, "start")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to start the service: %s", err)
|
||||
@@ -260,14 +280,13 @@ func handleServiceUninstallCommand(s service.Service) {
|
||||
}
|
||||
}
|
||||
|
||||
err := svcAction(s, "uninstall")
|
||||
if err != nil {
|
||||
if err := svcAction(s, "uninstall"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if runtime.GOOS == "darwin" {
|
||||
// Remove log files on cleanup and log errors.
|
||||
err = os.Remove(launchdStdoutPath)
|
||||
err := os.Remove(launchdStdoutPath)
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
log.Printf("removing stdout file: %s", err)
|
||||
}
|
||||
@@ -306,6 +325,9 @@ func configureService(c *service.Config) {
|
||||
} else if runtime.GOOS == "freebsd" {
|
||||
c.Option["SysvScript"] = freeBSDScript
|
||||
}
|
||||
|
||||
c.Option["RunComScript"] = openBSDScript
|
||||
c.Option["SvcInfo"] = fmt.Sprintf("%s %s", version.Full(), time.Now())
|
||||
}
|
||||
|
||||
// runInitdCommand runs init.d service command
|
||||
@@ -541,6 +563,20 @@ name="{{.Name}}"
|
||||
{{.Name}}_user="root"
|
||||
pidfile="/var/run/${name}.pid"
|
||||
command="/usr/sbin/daemon"
|
||||
command_args="-P ${pidfile} -f -r {{.WorkingDirectory}}/{{.Name}}"
|
||||
command_args="-p ${pidfile} -f -r {{.WorkingDirectory}}/{{.Name}}"
|
||||
run_rc_command "$1"
|
||||
`
|
||||
|
||||
const openBSDScript = `#!/bin/sh
|
||||
#
|
||||
# $OpenBSD: {{ .SvcInfo }}
|
||||
|
||||
daemon="{{.Path}}"
|
||||
daemon_flags={{ .Arguments | args }}
|
||||
|
||||
. /etc/rc.d/rc.subr
|
||||
|
||||
rc_bg=YES
|
||||
|
||||
rc_cmd $1
|
||||
`
|
||||
|
||||
432
internal/home/service_openbsd.go
Normal file
432
internal/home/service_openbsd.go
Normal file
@@ -0,0 +1,432 @@
|
||||
//go:build openbsd
|
||||
// +build openbsd
|
||||
|
||||
package home
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"text/template"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/stringutil"
|
||||
"github.com/kardianos/service"
|
||||
)
|
||||
|
||||
// OpenBSD Service Implementation
|
||||
//
|
||||
// The file contains OpenBSD implementations for service.System and
|
||||
// service.Service interfaces. It uses the default approach for RunCom-based
|
||||
// services systems, e.g. rc.d script. It's written as if it was in a separate
|
||||
// package and has only one internal dependency.
|
||||
//
|
||||
// TODO(e.burkov): Perhaps, file a PR to github.com/kardianos/service.
|
||||
|
||||
// sysVersion is the version of local service.System interface
|
||||
// implementation.
|
||||
const sysVersion = "openbsd-runcom"
|
||||
|
||||
func chooseSystem() {
|
||||
service.ChooseSystem(openbsdSystem{})
|
||||
}
|
||||
|
||||
// openbsdSystem is the service.System to be used on the OpenBSD.
|
||||
type openbsdSystem struct{}
|
||||
|
||||
// String implements service.System interface for openbsdSystem.
|
||||
func (openbsdSystem) String() string {
|
||||
return sysVersion
|
||||
}
|
||||
|
||||
// Detect implements service.System interface for openbsdSystem.
|
||||
func (openbsdSystem) Detect() (ok bool) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Interactive implements service.System interface for openbsdSystem.
|
||||
func (openbsdSystem) Interactive() (ok bool) {
|
||||
return os.Getppid() != 1
|
||||
}
|
||||
|
||||
// New implements service.System interface for openbsdSystem.
|
||||
func (openbsdSystem) New(i service.Interface, c *service.Config) (s service.Service, err error) {
|
||||
return &openbsdRunComService{
|
||||
i: i,
|
||||
cfg: c,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// openbsdRunComService is the RunCom-based service.Service to be used on the
|
||||
// OpenBSD.
|
||||
type openbsdRunComService struct {
|
||||
i service.Interface
|
||||
cfg *service.Config
|
||||
}
|
||||
|
||||
// Platform implements service.Service interface for *openbsdRunComService.
|
||||
func (*openbsdRunComService) Platform() (p string) {
|
||||
return "openbsd"
|
||||
}
|
||||
|
||||
// String implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) String() string {
|
||||
return stringutil.Coalesce(s.cfg.DisplayName, s.cfg.Name)
|
||||
}
|
||||
|
||||
// getBool returns the value of the given name from kv, assuming the value is a
|
||||
// boolean. If the value isn't found or is not of the type, the defaultValue is
|
||||
// returned.
|
||||
func getBool(kv service.KeyValue, name string, defaultValue bool) (val bool) {
|
||||
var ok bool
|
||||
if val, ok = kv[name].(bool); ok {
|
||||
return val
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// getString returns the value of the given name from kv, assuming the value is
|
||||
// a string. If the value isn't found or is not of the type, the defaultValue
|
||||
// is returned.
|
||||
func getString(kv service.KeyValue, name, defaultValue string) (val string) {
|
||||
var ok bool
|
||||
if val, ok = kv[name].(string); ok {
|
||||
return val
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// getFuncNiladic returns the value of the given name from kv, assuming the
|
||||
// value is a func(). If the value isn't found or is not of the type, the
|
||||
// defaultValue is returned.
|
||||
func getFuncNiladic(kv service.KeyValue, name string, defaultValue func()) (val func()) {
|
||||
var ok bool
|
||||
if val, ok = kv[name].(func()); ok {
|
||||
return val
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
const (
|
||||
// optionUserService is the UserService option name.
|
||||
optionUserService = "UserService"
|
||||
|
||||
// optionUserServiceDefault is the UserService option default value.
|
||||
optionUserServiceDefault = false
|
||||
|
||||
// errNoUserServiceRunCom is returned when the service uses some custom
|
||||
// path to script.
|
||||
errNoUserServiceRunCom errors.Error = "user services are not supported on " + sysVersion
|
||||
)
|
||||
|
||||
// scriptPath returns the absolute path to the script. It's commonly used to
|
||||
// send commands to the service.
|
||||
func (s *openbsdRunComService) scriptPath() (cp string, err error) {
|
||||
if getBool(s.cfg.Option, optionUserService, optionUserServiceDefault) {
|
||||
return "", errNoUserServiceRunCom
|
||||
}
|
||||
|
||||
const scriptPathPref = "/etc/rc.d"
|
||||
|
||||
return filepath.Join(scriptPathPref, s.cfg.Name), nil
|
||||
}
|
||||
|
||||
const (
|
||||
// optionRunComScript is the RunCom script option name.
|
||||
optionRunComScript = "RunComScript"
|
||||
|
||||
// runComScript is the default RunCom script.
|
||||
runComScript = `#!/bin/sh
|
||||
#
|
||||
# $OpenBSD: {{ .SvcInfo }}
|
||||
|
||||
daemon="{{.Path}}"
|
||||
daemon_flags={{ .Arguments | args }}
|
||||
|
||||
. /etc/rc.d/rc.subr
|
||||
|
||||
rc_bg=YES
|
||||
|
||||
rc_cmd $1
|
||||
`
|
||||
)
|
||||
|
||||
// template returns the script template to put into rc.d.
|
||||
func (s *openbsdRunComService) template() (t *template.Template) {
|
||||
tf := map[string]interface{}{
|
||||
"args": func(sl []string) string {
|
||||
return `"` + strings.Join(sl, " ") + `"`
|
||||
},
|
||||
}
|
||||
|
||||
return template.Must(template.New("").Funcs(tf).Parse(getString(
|
||||
s.cfg.Option,
|
||||
optionRunComScript,
|
||||
runComScript,
|
||||
)))
|
||||
}
|
||||
|
||||
// execPath returns the absolute path to the excutable to be run as a service.
|
||||
func (s *openbsdRunComService) execPath() (path string, err error) {
|
||||
if c := s.cfg; c != nil && len(c.Executable) != 0 {
|
||||
return filepath.Abs(c.Executable)
|
||||
}
|
||||
|
||||
if path, err = os.Executable(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return filepath.Abs(path)
|
||||
}
|
||||
|
||||
// annotate wraps errors.Annotate applying a common error format.
|
||||
func (s *openbsdRunComService) annotate(action string, err error) (annotated error) {
|
||||
return errors.Annotate(err, "%s %s %s service: %w", action, sysVersion, s.cfg.Name)
|
||||
}
|
||||
|
||||
// Install implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) Install() (err error) {
|
||||
defer func() { err = s.annotate("installing", err) }()
|
||||
|
||||
if err = s.writeScript(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.configureSysStartup(true)
|
||||
}
|
||||
|
||||
// configureSysStartup adds s into the group of packages started with system.
|
||||
func (s *openbsdRunComService) configureSysStartup(enable bool) (err error) {
|
||||
cmd := "enable"
|
||||
if !enable {
|
||||
cmd = "disable"
|
||||
}
|
||||
|
||||
var code int
|
||||
code, _, err = aghos.RunCommand("rcctl", cmd, s.cfg.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if code != 0 {
|
||||
return fmt.Errorf("rcctl finished with code %d", code)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeScript tries to write the script for the service.
|
||||
func (s *openbsdRunComService) writeScript() (err error) {
|
||||
var scriptPath string
|
||||
if scriptPath, err = s.scriptPath(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = os.Stat(scriptPath); !errors.Is(err, os.ErrNotExist) {
|
||||
return fmt.Errorf("script already exists at %s", scriptPath)
|
||||
}
|
||||
|
||||
var execPath string
|
||||
if execPath, err = s.execPath(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t := s.template()
|
||||
f, err := os.Create(scriptPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("creating rc.d script file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
err = t.Execute(f, &struct {
|
||||
*service.Config
|
||||
Path string
|
||||
SvcInfo string
|
||||
}{
|
||||
Config: s.cfg,
|
||||
Path: execPath,
|
||||
SvcInfo: getString(s.cfg.Option, "SvcInfo", s.String()),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.Annotate(
|
||||
os.Chmod(scriptPath, 0o755),
|
||||
"changing rc.d script file permissions: %w",
|
||||
)
|
||||
}
|
||||
|
||||
// Uninstall implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) Uninstall() (err error) {
|
||||
defer func() { err = s.annotate("uninstalling", err) }()
|
||||
|
||||
if err = s.configureSysStartup(false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var scriptPath string
|
||||
if scriptPath, err = s.scriptPath(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = os.Remove(scriptPath); errors.Is(err, os.ErrNotExist) {
|
||||
return service.ErrNotInstalled
|
||||
}
|
||||
|
||||
return errors.Annotate(err, "removing rc.d script: %w")
|
||||
}
|
||||
|
||||
// optionRunWait is the name of the option associated with function which waits
|
||||
// for the service to be stopped.
|
||||
const optionRunWait = "RunWait"
|
||||
|
||||
// runWait is the default function to wait for service to be stopped.
|
||||
func runWait() {
|
||||
sigChan := make(chan os.Signal, 3)
|
||||
signal.Notify(sigChan, syscall.SIGTERM, os.Interrupt)
|
||||
<-sigChan
|
||||
}
|
||||
|
||||
// Run implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) Run() (err error) {
|
||||
if err = s.i.Start(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
getFuncNiladic(s.cfg.Option, optionRunWait, runWait)()
|
||||
|
||||
return s.i.Stop(s)
|
||||
}
|
||||
|
||||
// runCom calls the script with the specified cmd.
|
||||
func (s *openbsdRunComService) runCom(cmd string) (out string, err error) {
|
||||
var scriptPath string
|
||||
if scriptPath, err = s.scriptPath(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// TODO(e.burkov): It's possible that os.ErrNotExist is caused by
|
||||
// something different than the service script's non-existence. Keep it
|
||||
// in mind, when replace the aghos.RunCommand.
|
||||
_, out, err = aghos.RunCommand(scriptPath, cmd)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return "", service.ErrNotInstalled
|
||||
}
|
||||
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Status implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) Status() (status service.Status, err error) {
|
||||
defer func() { err = s.annotate("getting status of", err) }()
|
||||
|
||||
var out string
|
||||
if out, err = s.runCom("check"); err != nil {
|
||||
return service.StatusUnknown, err
|
||||
}
|
||||
|
||||
name := s.cfg.Name
|
||||
switch out {
|
||||
case fmt.Sprintf("%s(ok)\n", name):
|
||||
return service.StatusRunning, nil
|
||||
case fmt.Sprintf("%s(failed)\n", name):
|
||||
return service.StatusStopped, nil
|
||||
default:
|
||||
return service.StatusUnknown, service.ErrNotInstalled
|
||||
}
|
||||
}
|
||||
|
||||
// Start implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) Start() (err error) {
|
||||
_, err = s.runCom("start")
|
||||
|
||||
return s.annotate("starting", err)
|
||||
}
|
||||
|
||||
// Stop implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) Stop() (err error) {
|
||||
_, err = s.runCom("stop")
|
||||
|
||||
return s.annotate("stopping", err)
|
||||
}
|
||||
|
||||
// Restart implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) Restart() (err error) {
|
||||
if err = s.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.Start()
|
||||
}
|
||||
|
||||
// Logger implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) Logger(errs chan<- error) (l service.Logger, err error) {
|
||||
if service.ChosenSystem().Interactive() {
|
||||
return service.ConsoleLogger, nil
|
||||
}
|
||||
|
||||
return s.SystemLogger(errs)
|
||||
}
|
||||
|
||||
// SystemLogger implements service.Service interface for *openbsdRunComService.
|
||||
func (s *openbsdRunComService) SystemLogger(errs chan<- error) (l service.Logger, err error) {
|
||||
return newSysLogger(s.cfg.Name, errs)
|
||||
}
|
||||
|
||||
// newSysLogger returns a stub service.Logger implementation.
|
||||
func newSysLogger(_ string, _ chan<- error) (service.Logger, error) {
|
||||
return sysLogger{}, nil
|
||||
}
|
||||
|
||||
// sysLogger wraps calls of the logging functions understandable for service
|
||||
// interfaces.
|
||||
type sysLogger struct{}
|
||||
|
||||
// Error implements service.Logger interface for sysLogger.
|
||||
func (sysLogger) Error(v ...interface{}) error {
|
||||
log.Error(fmt.Sprint(v...))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Warning implements service.Logger interface for sysLogger.
|
||||
func (sysLogger) Warning(v ...interface{}) error {
|
||||
log.Info("warning: %s", fmt.Sprint(v...))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Info implements service.Logger interface for sysLogger.
|
||||
func (sysLogger) Info(v ...interface{}) error {
|
||||
log.Info(fmt.Sprint(v...))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Errorf implements service.Logger interface for sysLogger.
|
||||
func (sysLogger) Errorf(format string, a ...interface{}) error {
|
||||
log.Error(format, a...)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Warningf implements service.Logger interface for sysLogger.
|
||||
func (sysLogger) Warningf(format string, a ...interface{}) error {
|
||||
log.Info("warning: %s", fmt.Sprintf(format, a...))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Infof implements service.Logger interface for sysLogger.
|
||||
func (sysLogger) Infof(format string, a ...interface{}) error {
|
||||
log.Info(format, a...)
|
||||
|
||||
return nil
|
||||
}
|
||||
6
internal/home/service_others.go
Normal file
6
internal/home/service_others.go
Normal file
@@ -0,0 +1,6 @@
|
||||
//go:build !openbsd
|
||||
// +build !openbsd
|
||||
|
||||
package home
|
||||
|
||||
func chooseSystem() {}
|
||||
@@ -210,15 +210,26 @@ type tlsConfigStatus struct {
|
||||
|
||||
// field ordering is important -- yaml fields will mirror ordering from here
|
||||
type tlsConfig struct {
|
||||
tlsConfigStatus `json:",inline"`
|
||||
tlsConfigStatus `json:",inline"`
|
||||
tlsConfigSettingsExt `json:",inline"`
|
||||
}
|
||||
|
||||
// tlsConfigSettingsExt is used to (un)marshal PrivateKeySaved to ensure that
|
||||
// clients don't send and receive previously saved private keys.
|
||||
type tlsConfigSettingsExt struct {
|
||||
tlsConfigSettings `json:",inline"`
|
||||
// If private key saved as a string, we set this flag to true
|
||||
// and omit key from answer.
|
||||
PrivateKeySaved bool `yaml:"-" json:"private_key_saved,inline"`
|
||||
}
|
||||
|
||||
func (t *TLSMod) handleTLSStatus(w http.ResponseWriter, _ *http.Request) {
|
||||
t.confLock.Lock()
|
||||
data := tlsConfig{
|
||||
tlsConfigSettings: t.conf,
|
||||
tlsConfigStatus: t.status,
|
||||
tlsConfigSettingsExt: tlsConfigSettingsExt{
|
||||
tlsConfigSettings: t.conf,
|
||||
},
|
||||
tlsConfigStatus: t.status,
|
||||
}
|
||||
t.confLock.Unlock()
|
||||
marshalTLS(w, data)
|
||||
@@ -231,19 +242,23 @@ func (t *TLSMod) handleTLSValidate(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if setts.PrivateKeySaved {
|
||||
setts.PrivateKey = t.conf.PrivateKey
|
||||
}
|
||||
|
||||
if !WebCheckPortAvailable(setts.PortHTTPS) {
|
||||
httpError(w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", setts.PortHTTPS)
|
||||
return
|
||||
}
|
||||
|
||||
status := tlsConfigStatus{}
|
||||
if tlsLoadConfig(&setts, &status) {
|
||||
if tlsLoadConfig(&setts.tlsConfigSettings, &status) {
|
||||
status = validateCertificates(string(setts.CertificateChainData), string(setts.PrivateKeyData), setts.ServerName)
|
||||
}
|
||||
|
||||
data := tlsConfig{
|
||||
tlsConfigSettings: setts,
|
||||
tlsConfigStatus: status,
|
||||
tlsConfigSettingsExt: setts,
|
||||
tlsConfigStatus: status,
|
||||
}
|
||||
marshalTLS(w, data)
|
||||
}
|
||||
@@ -290,16 +305,20 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if data.PrivateKeySaved {
|
||||
data.PrivateKey = t.conf.PrivateKey
|
||||
}
|
||||
|
||||
if !WebCheckPortAvailable(data.PortHTTPS) {
|
||||
httpError(w, http.StatusBadRequest, "port %d is not available, cannot enable HTTPS on it", data.PortHTTPS)
|
||||
return
|
||||
}
|
||||
|
||||
status := tlsConfigStatus{}
|
||||
if !tlsLoadConfig(&data, &status) {
|
||||
if !tlsLoadConfig(&data.tlsConfigSettings, &status) {
|
||||
data2 := tlsConfig{
|
||||
tlsConfigSettings: data,
|
||||
tlsConfigStatus: t.status,
|
||||
tlsConfigSettingsExt: data,
|
||||
tlsConfigStatus: t.status,
|
||||
}
|
||||
marshalTLS(w, data2)
|
||||
|
||||
@@ -308,7 +327,7 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
status = validateCertificates(string(data.CertificateChainData), string(data.PrivateKeyData), data.ServerName)
|
||||
|
||||
restartHTTPS := t.setConfig(data, status)
|
||||
restartHTTPS := t.setConfig(data.tlsConfigSettings, status)
|
||||
t.setCertFileTime()
|
||||
onConfigModified()
|
||||
|
||||
@@ -320,8 +339,8 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
data2 := tlsConfig{
|
||||
tlsConfigSettings: data,
|
||||
tlsConfigStatus: t.status,
|
||||
tlsConfigSettingsExt: data,
|
||||
tlsConfigStatus: t.status,
|
||||
}
|
||||
|
||||
marshalTLS(w, data2)
|
||||
@@ -335,7 +354,7 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) {
|
||||
// goroutine due to the same reason.
|
||||
if restartHTTPS {
|
||||
go func() {
|
||||
Context.web.TLSConfigChanged(context.Background(), data)
|
||||
Context.web.TLSConfigChanged(context.Background(), data.tlsConfigSettings)
|
||||
}()
|
||||
}
|
||||
}
|
||||
@@ -514,8 +533,8 @@ func parsePrivateKey(der []byte) (crypto.PrivateKey, string, error) {
|
||||
}
|
||||
|
||||
// unmarshalTLS handles base64-encoded certificates transparently
|
||||
func unmarshalTLS(r *http.Request) (tlsConfigSettings, error) {
|
||||
data := tlsConfigSettings{}
|
||||
func unmarshalTLS(r *http.Request) (tlsConfigSettingsExt, error) {
|
||||
data := tlsConfigSettingsExt{}
|
||||
err := json.NewDecoder(r.Body).Decode(&data)
|
||||
if err != nil {
|
||||
return data, fmt.Errorf("failed to parse new TLS config json: %w", err)
|
||||
@@ -559,8 +578,8 @@ func marshalTLS(w http.ResponseWriter, data tlsConfig) {
|
||||
}
|
||||
|
||||
if data.PrivateKey != "" {
|
||||
encoded := base64.StdEncoding.EncodeToString([]byte(data.PrivateKey))
|
||||
data.PrivateKey = encoded
|
||||
data.PrivateKeySaved = true
|
||||
data.PrivateKey = ""
|
||||
}
|
||||
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtime"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
@@ -684,7 +685,7 @@ func upgradeSchema11to12(diskConf yobj) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
dns[field] = Duration{Duration: time.Duration(qlogIvl) * 24 * time.Hour}
|
||||
dns[field] = aghtime.Duration{Duration: time.Duration(qlogIvl) * 24 * time.Hour}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtime"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -425,7 +426,7 @@ func TestUpgradeSchema11to12(t *testing.T) {
|
||||
name string
|
||||
}{{
|
||||
ivl: 1,
|
||||
want: Duration{Duration: 24 * time.Hour},
|
||||
want: aghtime.Duration{Duration: 24 * time.Hour},
|
||||
wantErr: "",
|
||||
name: "success",
|
||||
}, {
|
||||
@@ -462,8 +463,8 @@ func TestUpgradeSchema11to12(t *testing.T) {
|
||||
newDNSConf, ok = dnsVal.(yobj)
|
||||
require.True(t, ok)
|
||||
|
||||
var newIvl Duration
|
||||
newIvl, ok = newDNSConf["querylog_interval"].(Duration)
|
||||
var newIvl aghtime.Duration
|
||||
newIvl, ok = newDNSConf["querylog_interval"].(aghtime.Duration)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, tc.want, newIvl)
|
||||
@@ -504,8 +505,8 @@ func TestUpgradeSchema11to12(t *testing.T) {
|
||||
ivl, ok = dnsVal["querylog_interval"]
|
||||
require.True(t, ok)
|
||||
|
||||
var ivlVal Duration
|
||||
ivlVal, ok = ivl.(Duration)
|
||||
var ivlVal aghtime.Duration
|
||||
ivlVal, ok = ivl.(aghtime.Duration)
|
||||
require.True(t, ok)
|
||||
|
||||
assert.Equal(t, 90*24*time.Hour, ivlVal.Duration)
|
||||
|
||||
@@ -90,29 +90,7 @@ func createObject(conf Config) (s *statsCtx, err error) {
|
||||
firstID := id - s.conf.limit - 1
|
||||
unitDel := 0
|
||||
|
||||
// TODO(a.garipov): See if this is actually necessary. Looks
|
||||
// like a rather bizarre solution.
|
||||
errStop := errors.Error("stop iteration")
|
||||
forEachBkt := func(name []byte, _ *bolt.Bucket) (cberr error) {
|
||||
nameID := uint32(btoi(name))
|
||||
if nameID < firstID {
|
||||
cberr = tx.DeleteBucket(name)
|
||||
if cberr != nil {
|
||||
log.Debug("stats: tx.DeleteBucket: %s", cberr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug("stats: deleted unit %d", nameID)
|
||||
unitDel++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return errStop
|
||||
}
|
||||
|
||||
err = tx.ForEach(forEachBkt)
|
||||
err = tx.ForEach(newBucketWalker(tx, &unitDel, firstID))
|
||||
if err != nil && !errors.Is(err, errStop) {
|
||||
log.Debug("stats: deleting units: %s", err)
|
||||
}
|
||||
@@ -141,6 +119,39 @@ func createObject(conf Config) (s *statsCtx, err error) {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// TODO(a.garipov): See if this is actually necessary. Looks like a rather
|
||||
// bizarre solution.
|
||||
const errStop errors.Error = "stop iteration"
|
||||
|
||||
// newBucketWalker returns a new bucket walker that deletes old units. The
|
||||
// integer that unitDelPtr points to is incremented for every successful
|
||||
// deletion. If the bucket isn't deleted, f returns errStop.
|
||||
func newBucketWalker(
|
||||
tx *bolt.Tx,
|
||||
unitDelPtr *int,
|
||||
firstID uint32,
|
||||
) (f func(name []byte, b *bolt.Bucket) (err error)) {
|
||||
return func(name []byte, _ *bolt.Bucket) (err error) {
|
||||
nameID, ok := unitNameToID(name)
|
||||
if !ok || nameID < firstID {
|
||||
err = tx.DeleteBucket(name)
|
||||
if err != nil {
|
||||
log.Debug("stats: tx.DeleteBucket: %s", err)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debug("stats: deleted unit %d (name %x)", nameID, name)
|
||||
|
||||
*unitDelPtr++
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return errStop
|
||||
}
|
||||
}
|
||||
|
||||
func (s *statsCtx) Start() {
|
||||
s.initWeb()
|
||||
go s.periodicFlush()
|
||||
@@ -215,21 +226,28 @@ func (s *statsCtx) commitTxn(tx *bolt.Tx) {
|
||||
log.Tracef("tx.Commit")
|
||||
}
|
||||
|
||||
// Get unit name
|
||||
func unitName(id uint32) []byte {
|
||||
return itob(uint64(id))
|
||||
// bucketNameLen is the length of a bucket, a 64-bit unsigned integer.
|
||||
//
|
||||
// TODO(a.garipov): Find out why a 64-bit integer is used when IDs seem to
|
||||
// always be 32 bits.
|
||||
const bucketNameLen = 8
|
||||
|
||||
// idToUnitName converts a numerical ID into a database unit name.
|
||||
func idToUnitName(id uint32) (name []byte) {
|
||||
name = make([]byte, bucketNameLen)
|
||||
binary.BigEndian.PutUint64(name, uint64(id))
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
// Convert integer to 8-byte array (big endian)
|
||||
func itob(v uint64) []byte {
|
||||
b := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(b, v)
|
||||
return b
|
||||
}
|
||||
// unitNameToID converts a database unit name into a numerical ID. ok is false
|
||||
// if name is not a valid database unit name.
|
||||
func unitNameToID(name []byte) (id uint32, ok bool) {
|
||||
if len(name) < bucketNameLen {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Convert 8-byte array (big endian) to integer
|
||||
func btoi(b []byte) uint64 {
|
||||
return binary.BigEndian.Uint64(b)
|
||||
return uint32(binary.BigEndian.Uint64(name)), true
|
||||
}
|
||||
|
||||
// Flush the current unit to DB and delete an old unit when a new hour is started
|
||||
@@ -282,7 +300,7 @@ func (s *statsCtx) periodicFlush() {
|
||||
|
||||
// Delete unit's data from file
|
||||
func (s *statsCtx) deleteUnit(tx *bolt.Tx, id uint32) bool {
|
||||
err := tx.DeleteBucket(unitName(id))
|
||||
err := tx.DeleteBucket(idToUnitName(id))
|
||||
if err != nil {
|
||||
log.Tracef("stats: bolt DeleteBucket: %s", err)
|
||||
|
||||
@@ -357,7 +375,7 @@ func deserialize(u *unit, udb *unitDB) {
|
||||
func (s *statsCtx) flushUnitToDB(tx *bolt.Tx, id uint32, udb *unitDB) bool {
|
||||
log.Tracef("Flushing unit %d", id)
|
||||
|
||||
bkt, err := tx.CreateBucketIfNotExists(unitName(id))
|
||||
bkt, err := tx.CreateBucketIfNotExists(idToUnitName(id))
|
||||
if err != nil {
|
||||
log.Error("tx.CreateBucketIfNotExists: %s", err)
|
||||
return false
|
||||
@@ -381,7 +399,7 @@ func (s *statsCtx) flushUnitToDB(tx *bolt.Tx, id uint32, udb *unitDB) bool {
|
||||
}
|
||||
|
||||
func (s *statsCtx) loadUnitFromDB(tx *bolt.Tx, id uint32) *unitDB {
|
||||
bkt := tx.Bucket(unitName(id))
|
||||
bkt := tx.Bucket(idToUnitName(id))
|
||||
if bkt == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
// Tools.
|
||||
_ "github.com/fzipp/gocyclo/cmd/gocyclo"
|
||||
_ "github.com/golangci/misspell/cmd/misspell"
|
||||
_ "github.com/gordonklaus/ineffassign"
|
||||
|
||||
@@ -4,6 +4,13 @@
|
||||
|
||||
## v0.107: API changes
|
||||
|
||||
### The new field `"private_key_saved"` in `TlsConfig`
|
||||
|
||||
* The new field `"private_key_saved"` in `POST /control/tls/configure`,
|
||||
`POST /control/tls/validate` and `GET /control/tls/status` is true if the
|
||||
private key was previously saved as a string and now the private key omitted
|
||||
from communication between server and client due to security issues.
|
||||
|
||||
### The new field `"cache_optimistic"` in DNS configuration
|
||||
|
||||
* The new optional field `"cache_optimistic"` in `POST /control/dns_config`
|
||||
|
||||
@@ -2075,6 +2075,14 @@
|
||||
'private_key':
|
||||
'type': 'string'
|
||||
'description': 'Base64 string with PEM-encoded private key'
|
||||
'private_key_saved':
|
||||
'type': 'boolean'
|
||||
'example': true
|
||||
'description': >
|
||||
Set to true if the user has previously saved a private key as
|
||||
a string. This is used so that the server and the client don't
|
||||
have to send the private key between each other every time,
|
||||
which might lead to security issues.
|
||||
'certificate_path':
|
||||
'type': 'string'
|
||||
'description': 'Path to certificate file'
|
||||
|
||||
@@ -49,9 +49,12 @@ trap not_found EXIT
|
||||
|
||||
# Warnings
|
||||
|
||||
go_version="$( "$GO" version )"
|
||||
readonly go_version
|
||||
|
||||
go_min_version='go1.16'
|
||||
go_version_msg="
|
||||
warning: your go version is different from the recommended minimal one (${go_min_version}).
|
||||
warning: your go version (${go_version}) is different from the recommended minimal one (${go_min_version}).
|
||||
if you have the version installed, please set the GO environment variable.
|
||||
for example:
|
||||
|
||||
@@ -59,7 +62,8 @@ for example:
|
||||
"
|
||||
readonly go_min_version go_version_msg
|
||||
|
||||
case "$( "$GO" version )"
|
||||
|
||||
case "$go_version"
|
||||
in
|
||||
('go version'*"$go_min_version"*)
|
||||
# Go on.
|
||||
@@ -197,12 +201,12 @@ golint --set_exit_status ./...
|
||||
|
||||
# Apply more lax standards to the code we haven't properly refactored yet.
|
||||
gocyclo --over 17 ./internal/dhcpd/ ./internal/dnsforward/\
|
||||
./internal/filtering/ ./internal/home/ ./internal/querylog/\
|
||||
./internal/stats/ ./internal/updater/
|
||||
./internal/filtering/ ./internal/home/ ./internal/querylog/
|
||||
|
||||
# Apply stricter standards to new or vetted code
|
||||
# Apply stricter standards to new or somewhat refactored code.
|
||||
gocyclo --over 10 ./internal/aghio/ ./internal/aghnet/ ./internal/aghos/\
|
||||
./internal/aghtest/ ./internal/tools/ ./internal/version/ ./main.go
|
||||
./internal/aghtest/ ./internal/stats/ ./internal/tools/\
|
||||
./internal/updater/ ./internal/version/ ./main.go
|
||||
|
||||
gosec --quiet $go_files
|
||||
|
||||
|
||||
@@ -46,4 +46,5 @@ not_found() {
|
||||
}
|
||||
trap not_found EXIT
|
||||
|
||||
git ls-files -- '*.md' '*.yaml' '*.yml' | xargs misspell --error
|
||||
git ls-files -- '*.md' '*.yaml' '*.yml' 'client/src/__locales/en.json'\
|
||||
| xargs misspell --error
|
||||
|
||||
Reference in New Issue
Block a user