From 050e996a35b1f26f1c03af7eda75584afad9bfc1 Mon Sep 17 00:00:00 2001 From: ArtemBaskal Date: Thu, 3 Sep 2020 19:33:49 +0300 Subject: [PATCH 01/19] - client: Fix superfluous character in de locale --- client/src/__locales/de.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/__locales/de.json b/client/src/__locales/de.json index 2a9784ad..72f7989f 100644 --- a/client/src/__locales/de.json +++ b/client/src/__locales/de.json @@ -45,7 +45,7 @@ "dhcp_warning": "Wenn Sie den DHCP-Server trotzdem aktivieren möchten, stellen Sie sicher, dass sich in Ihrem Netzwerk kein anderer aktiver DHCP-Server befindet. Andernfalls kann es bei angeschlossenen Geräten zu einem Ausfall des Internets kommen!", "dhcp_error": "Es konnte nicht ermittelt werden, ob es einen anderen DHCP-Server im Netzwerk gibt.", "dhcp_static_ip_error": "Um den DHCP-Server nutzen zu können, muss eine statische IP-Adresse festgelegt werden. Es konnte nicht ermittelt werden, ob diese Netzwerkschnittstelle mit statischer IP-Adresse konfiguriert ist. Bitte legen Sie eine statische IP-Adresse manuell fest.", - "dhcp_dynamic_ip_found": "Ihr System verwendet die dynamische Konfiguration der IP-Adresse für die Schnittstelle <0>{{interfaceName}}. Um den DHCP-Server nutzen zu können, muss eine statische IP-Adresse festgelegt werden. Ihre aktuelle IP-Adresse ist <0>{{ipAddress}}}. Diese IP-Adresse wird automatisch als statisch festgelegt, sobald Sie auf die Schaltfläche „DHCP aktivieren” klicken.", + "dhcp_dynamic_ip_found": "Ihr System verwendet die dynamische Konfiguration der IP-Adresse für die Schnittstelle <0>{{interfaceName}}. Um den DHCP-Server nutzen zu können, muss eine statische IP-Adresse festgelegt werden. Ihre aktuelle IP-Adresse ist <0>{{ipAddress}}. Diese IP-Adresse wird automatisch als statisch festgelegt, sobald Sie auf die Schaltfläche „DHCP aktivieren” klicken.", "dhcp_lease_added": "Statischer Lease „{{key}}” erfolgreich hinzugefügt", "dhcp_lease_deleted": "Statischer Lease „{{key}}” erfolgreich entfernt", "dhcp_new_static_lease": "Neuer statischer Lease", @@ -99,7 +99,7 @@ "no_clients_found": "Keine Clients gefunden", "general_statistics": "Allgemeine Statistiken", "number_of_dns_query_days": "Anzahl der in den letzten {{count}} Tagen verarbeiteten DNS-Anfragen", - "number_of_dns_query_days_plural": "Anzahl der DNS-Abfragen, die in den letzten {{count}}} Tagen verarbeitet wurden", + "number_of_dns_query_days_plural": "Anzahl der DNS-Abfragen, die in den letzten {{count}} Tagen verarbeitet wurden", "number_of_dns_query_24_hours": "Anzahl der in den letzten 24 Stunden durchgeführten DNS-Anfragen", "number_of_dns_query_blocked_24_hours": "Anzahl der durch Werbefilter und Host-Blocklisten geblockten DNS-Anfragen", "number_of_dns_query_blocked_24_hours_by_sec": "Anzahl der durch das AdGuard-Modul für Internet-Sicherheit blockierten DNS-Anfragen", From 9e33bd52599c2039603d99f93db461cc6a6a23f4 Mon Sep 17 00:00:00 2001 From: ArtemBaskal Date: Thu, 3 Sep 2020 20:35:20 +0300 Subject: [PATCH 02/19] - client: Display service name for blocked services --- client/src/components/Logs/Cells/DomainCell.js | 8 +++++++- client/src/helpers/helpers.js | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/client/src/components/Logs/Cells/DomainCell.js b/client/src/components/Logs/Cells/DomainCell.js index 4333089c..47d14846 100644 --- a/client/src/components/Logs/Cells/DomainCell.js +++ b/client/src/components/Logs/Cells/DomainCell.js @@ -14,6 +14,7 @@ import IconTooltip from './IconTooltip'; const DomainCell = ({ answer_dnssec, + service_name, client_proto, domain, time, @@ -49,6 +50,10 @@ const DomainCell = ({ protocol, }; + if (service_name) { + requestDetailsObj.check_service = service_name; + } + const sourceData = getSourceData(tracker); const knownTrackerDataObj = { @@ -98,7 +103,7 @@ const DomainCell = ({ xlinkHref='privacy' contentItemClass='key-colon' renderContent={renderContent} place='bottom' />
-
{domain}
+
{service_name || domain}
{details && isDetailed &&
{details}
} @@ -112,6 +117,7 @@ DomainCell.propTypes = { domain: propTypes.string.isRequired, time: propTypes.string.isRequired, type: propTypes.string.isRequired, + service_name: propTypes.string, tracker: propTypes.object, }; diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index 9fdd9fad..fa3a5046 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -97,7 +97,7 @@ export const normalizeLogs = (logs) => logs.map((log) => { filterId, rule, status, - serviceName: service_name, + service_name, originalAnswer: original_answer, originalResponse: processResponse(original_answer), tracker: getTrackerData(domain), From b54ce85d3d5f39957d0a2c3625c04e4936c40d94 Mon Sep 17 00:00:00 2001 From: ArtemBaskal Date: Thu, 3 Sep 2020 20:57:22 +0300 Subject: [PATCH 03/19] - client: Fix top clients alignment --- client/src/components/ui/Card.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/components/ui/Card.css b/client/src/components/ui/Card.css index cef0e71d..5930d881 100644 --- a/client/src/components/ui/Card.css +++ b/client/src/components/ui/Card.css @@ -16,7 +16,11 @@ .card-table-overflow--limited { overflow-y: auto; - max-height: 280px; + max-height: 17.5rem; +} + +.card-table-overflow--limited.clients__table { + max-height: 18rem; } .card-actions { From 07b6cc24b77c2bc300278a518072bb66280173b0 Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Thu, 27 Aug 2020 14:20:17 +0300 Subject: [PATCH 04/19] * dnsproxy v0.32.0 --- go.mod | 5 +- go.sum | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 210 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 1a81eba8..476a496f 100644 --- a/go.mod +++ b/go.mod @@ -3,13 +3,12 @@ module github.com/AdguardTeam/AdGuardHome go 1.14 require ( - github.com/AdguardTeam/dnsproxy v0.31.1 + github.com/AdguardTeam/dnsproxy v0.32.0 github.com/AdguardTeam/golibs v0.4.2 github.com/AdguardTeam/urlfilter v0.12.2 github.com/NYTimes/gziphandler v1.1.1 github.com/fsnotify/fsnotify v1.4.9 github.com/gobuffalo/packr v1.30.1 - github.com/google/go-cmp v0.4.0 // indirect github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 github.com/insomniacslk/dhcp v0.0.0-20200621044212-d74cd86ad5b8 github.com/joomcode/errorx v1.0.1 @@ -24,7 +23,7 @@ require ( github.com/u-root/u-root v6.0.0+incompatible go.etcd.io/bbolt v1.3.4 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 - golang.org/x/net v0.0.0-20200625001655-4c5254603344 + golang.org/x/net v0.0.0-20200707034311-ab3426394381 golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 gopkg.in/natefinch/lumberjack.v2 v2.0.0 gopkg.in/yaml.v2 v2.3.0 diff --git a/go.sum b/go.sum index 794cd232..d1e535fa 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,14 @@ -github.com/AdguardTeam/dnsproxy v0.31.1 h1:kYnlLGM20LjPlEH+fqwCy08gMP5EVdp1FRaJ7uzyIJ0= -github.com/AdguardTeam/dnsproxy v0.31.1/go.mod h1:hOYFV9TW+pd5XKYz7KZf2FFD8SvSPqjyGTxUae86s58= +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= +dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= +dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= +dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= +dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= +github.com/AdguardTeam/dnsproxy v0.32.0 h1:taULDOMubiQSvRLynn8GlfMunhKaVryCBd/OkM++YFU= +github.com/AdguardTeam/dnsproxy v0.32.0/go.mod h1:ZLDrKIypYxBDz2N9FQHgeehuHrwTbuhZXdGwNySshbw= github.com/AdguardTeam/golibs v0.4.0/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= github.com/AdguardTeam/golibs v0.4.2 h1:7M28oTZFoFwNmp8eGPb3ImmYbxGaJLyQXeIFVHjME0o= github.com/AdguardTeam/golibs v0.4.2/go.mod h1:skKsDKIBB7kkFflLJBpfGX+G8QFTx0WKUzB6TIgtUj4= @@ -20,21 +29,35 @@ github.com/ameshkov/dnscrypt v1.1.0 h1:2vAt5dD6ZmqlAxEAfzRcLBnkvdf8NI46Kn9InSwQb github.com/ameshkov/dnscrypt v1.1.0/go.mod h1:ikduAxNLCTEfd1AaCgpIA5TgroIVQ8JY3Vb095fiFJg= github.com/ameshkov/dnsstamps v1.0.1 h1:LhGvgWDzhNJh+kBQd/AfUlq1vfVe109huiXw4JhnPug= github.com/ameshkov/dnsstamps v1.0.1/go.mod h1:Ii3eUu73dx4Vw5O4wjzmT5+lkCwovjzaEZZ4gKyIH5A= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beefsack/go-rate v0.0.0-20180408011153-efa7637bb9b6 h1:KXlsf+qt/X5ttPGEjR0tPH1xaWWoKBEg9Q1THAj2h3I= github.com/beefsack/go-rate v0.0.0-20180408011153-efa7637bb9b6/go.mod h1:6YNgTHLutezwnBvyneBbwvB8C82y3dcoOj5EQJIdGXA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= +github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= +github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= +github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/go-test/deep v1.0.5 h1:AKODKU3pDH1RzZzm6YZu77YWtEAq6uh1rLIAQlay2qc= @@ -49,12 +72,43 @@ github.com/gobuffalo/packr v1.30.1 h1:hu1fuVR3fXEZR7rXNW3h8rqSML8EVAf6KNm0NKO/wK github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= github.com/gobuffalo/packr/v2 v2.5.1 h1:TFOeY2VoGamPjQLiNDT3mn//ytzk236VMO2j7iHxJR4= github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= +github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714 h1:/jC7qQFrv8CrSJVmaolDVOxTfS9kc36uB6H40kdbQq8= github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -62,16 +116,20 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/insomniacslk/dhcp v0.0.0-20200621044212-d74cd86ad5b8 h1:u+vle+5E78+cT/CSMD5/Y3NUpMgA83Yu2KhG+Zbco/k= github.com/insomniacslk/dhcp v0.0.0-20200621044212-d74cd86ad5b8/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw= +github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joomcode/errorx v1.0.1 h1:CalpDWz14ZHd68fIqluJasJosAewpz2TFaJALrUxjrk= github.com/joomcode/errorx v1.0.1/go.mod h1:kgco15ekB6cs+4Xjzo7SPeXzx38PbJzBwbnu9qfVNHQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/kardianos/service v1.1.0 h1:QV2SiEeWK42P0aEmGcsAgjApw/lRxkwopvT+Gu6t1/0= github.com/kardianos/service v1.1.0/go.mod h1:RrJI2xn5vve/r32U5suTbeaSGoMU6GbNPoj36CVYcHc= github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU= github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -79,38 +137,94 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lucas-clemente/quic-go v0.18.0 h1:JhQDdqxdwdmGdKsKgXi1+coHRoGhvU6z0rNzOJqZ/4o= +github.com/lucas-clemente/quic-go v0.18.0/go.mod h1:yXttHsSNxQi8AWijC/vLP+OJczXqzHSOcJrM5ITUlCg= +github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/marten-seemann/qpack v0.2.0/go.mod h1:F7Gl5L1jIgN1D11ucXefiuJS9UMVP2opoCp2jDKb7wc= +github.com/marten-seemann/qtls v0.10.0 h1:ECsuYUKalRL240rRD4Ri33ISb7kAQ3qGDlrrl55b2pc= +github.com/marten-seemann/qtls v0.10.0/go.mod h1:UvMd1oaYDACI99/oZUYLzMCkBXQVT0aGm99sJhbT8hs= +github.com/marten-seemann/qtls-go1-15 v0.1.0 h1:i/YPXVxz8q9umso/5y474CNcHmTpA+5DH+mFPjx6PZg= +github.com/marten-seemann/qtls-go1-15 v0.1.0/go.mod h1:GyFwywLKkRt+6mfU99csTEY1joMZz5vmB1WNZH3P81I= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7 h1:lez6TS6aAau+8wXUP3G9I3TGlmPFEq2CTxBaRqY6AGE= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065 h1:aFkJ6lx4FPip+S+Uw4aTegFMct9shDvP+79PsSxpm3w= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg= github.com/miekg/dns v1.1.29/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= +github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= +github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shirou/gopsutil v2.20.3+incompatible h1:0JVooMPsT7A7HqEYdydp/OfjSOYSjhXV7w1hkKj/NPQ= github.com/shirou/gopsutil v2.20.3+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= +github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= +github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= +github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= +github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= +github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= +github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= +github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= +github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= +github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= +github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= +github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= +github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= +github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= +github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= +github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= +github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c h1:gqEdF4VwBu3lTKGHS9rXE9x1/pEaSwCXRLOZRF6qtlw= github.com/sparrc/go-ping v0.0.0-20190613174326-4e5b6552494c/go.mod h1:eMyUVp6f/5jnzM+3zahzl7q6UXLbgSc3MKg/+ow9QW0= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -126,25 +240,47 @@ github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/u-root/u-root v6.0.0+incompatible h1:YqPGmRoRyYmeg17KIWFRSyVq6LX5T6GSzawyA6wG6EE= github.com/u-root/u-root v6.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +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= +golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8 h1:fpnn/HnJONpIu6hkXi1u/7rR0NzilgWr4T0JmWkEitk= -golang.org/x/crypto v0.0.0-20200403201458-baeed622b8d8/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -153,46 +289,112 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= +google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= From d53e32259a3a1b5f55b3e1730339f1a0410eb1be Mon Sep 17 00:00:00 2001 From: Simon Zolin Date: Thu, 27 Aug 2020 15:03:07 +0300 Subject: [PATCH 05/19] + DNS: "port_dns_over_quic" setting --- AGHTechDoc.md | 2 ++ dnsforward/config.go | 5 +++++ dnsforward/dnsforward_http.go | 2 +- home/config.go | 16 +++++++++------- home/control_update.go | 4 +++- home/dns.go | 13 +++++++++++++ home/tls.go | 2 ++ openapi/openapi.yaml | 5 +++++ 8 files changed, 40 insertions(+), 9 deletions(-) diff --git a/AGHTechDoc.md b/AGHTechDoc.md index e5e582ec..0dcb001b 100644 --- a/AGHTechDoc.md +++ b/AGHTechDoc.md @@ -743,6 +743,7 @@ Response: "server_name":"...", "port_https":443, "port_dns_over_tls":853, + "port_dns_over_quic":784, "certificate_chain":"...", "private_key":"...", "certificate_path":"...", @@ -774,6 +775,7 @@ Request: "force_https":false, "port_https":443, "port_dns_over_tls":853, + "port_dns_over_quic":784, "certificate_chain":"...", "private_key":"...", "certificate_path":"...", // if set, certificate_chain must be empty diff --git a/dnsforward/config.go b/dnsforward/config.go index 69af11eb..5d06b9dc 100644 --- a/dnsforward/config.go +++ b/dnsforward/config.go @@ -92,6 +92,7 @@ type FilteringConfig struct { // TLSConfig is the TLS configuration for HTTPS, DNS-over-HTTPS, and DNS-over-TLS type TLSConfig struct { TLSListenAddr *net.TCPAddr `yaml:"-" json:"-"` + QUICListenAddr *net.UDPAddr `yaml:"-" json:"-"` StrictSNICheck bool `yaml:"strict_sni_check" json:"-"` // Reject connection if the client uses server name (in SNI) that doesn't match the certificate CertificateChain string `yaml:"certificate_chain" json:"certificate_chain"` // PEM-encoded certificates chain @@ -153,6 +154,10 @@ func (s *Server) createProxyConfig() (proxy.Config, error) { MaxGoroutines: int(s.conf.MaxGoroutines), } + if s.conf.QUICListenAddr != nil { + proxyConfig.QUICListenAddr = []*net.UDPAddr{s.conf.QUICListenAddr} + } + if s.conf.CacheSize != 0 { proxyConfig.CacheEnabled = true proxyConfig.CacheSizeBytes = int(s.conf.CacheSize) diff --git a/dnsforward/dnsforward_http.go b/dnsforward/dnsforward_http.go index 63e82d95..79e4ded7 100644 --- a/dnsforward/dnsforward_http.go +++ b/dnsforward/dnsforward_http.go @@ -270,7 +270,7 @@ func ValidateUpstreams(upstreams []string) error { return nil } -var protocols = []string{"tls://", "https://", "tcp://", "sdns://"} +var protocols = []string{"tls://", "https://", "tcp://", "sdns://", "quic://"} func validateUpstream(u string) (bool, error) { // Check if user tries to specify upstream for domain diff --git a/home/config.go b/home/config.go index d0fc6396..348e72fa 100644 --- a/home/config.go +++ b/home/config.go @@ -92,11 +92,12 @@ type dnsConfig struct { } type tlsConfigSettings struct { - Enabled bool `yaml:"enabled" json:"enabled"` // Enabled is the encryption (DOT/DOH/HTTPS) status - ServerName string `yaml:"server_name" json:"server_name,omitempty"` // ServerName is the hostname of your HTTPS/TLS server - ForceHTTPS bool `yaml:"force_https" json:"force_https,omitempty"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect - PortHTTPS int `yaml:"port_https" json:"port_https,omitempty"` // HTTPS port. If 0, HTTPS will be disabled - PortDNSOverTLS int `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"` // DNS-over-TLS port. If 0, DOT will be disabled + Enabled bool `yaml:"enabled" json:"enabled"` // Enabled is the encryption (DOT/DOH/HTTPS) status + ServerName string `yaml:"server_name" json:"server_name,omitempty"` // ServerName is the hostname of your HTTPS/TLS server + ForceHTTPS bool `yaml:"force_https" json:"force_https,omitempty"` // ForceHTTPS: if true, forces HTTP->HTTPS redirect + PortHTTPS int `yaml:"port_https" json:"port_https,omitempty"` // HTTPS port. If 0, HTTPS will be disabled + PortDNSOverTLS int `yaml:"port_dns_over_tls" json:"port_dns_over_tls,omitempty"` // DNS-over-TLS port. If 0, DOT will be disabled + PortDNSOverQUIC uint16 `yaml:"port_dns_over_quic" json:"port_dns_over_quic,omitempty"` // DNS-over-QUIC port. If 0, DoQ will be disabled // Allow DOH queries via unencrypted HTTP (e.g. for reverse proxying) AllowUnencryptedDOH bool `yaml:"allow_unencrypted_doh" json:"allow_unencrypted_doh"` @@ -124,8 +125,9 @@ var config = configuration{ FiltersUpdateIntervalHours: 24, }, TLS: tlsConfigSettings{ - PortHTTPS: 443, - PortDNSOverTLS: 853, // needs to be passed through to dnsproxy + PortHTTPS: 443, + PortDNSOverTLS: 853, // needs to be passed through to dnsproxy + PortDNSOverQUIC: 784, }, logSettings: logSettings{ LogCompress: false, diff --git a/home/control_update.go b/home/control_update.go index fb160900..b8f6bcbe 100644 --- a/home/control_update.go +++ b/home/control_update.go @@ -99,7 +99,9 @@ func getVersionResp(info update.VersionInfo) []byte { Context.tls.WriteDiskConfig(&tlsConf) if runtime.GOOS != "windows" && - ((tlsConf.Enabled && (tlsConf.PortHTTPS < 1024 || tlsConf.PortDNSOverTLS < 1024)) || + ((tlsConf.Enabled && (tlsConf.PortHTTPS < 1024 || + tlsConf.PortDNSOverTLS < 1024 || + tlsConf.PortDNSOverQUIC < 1024)) || config.BindPort < 1024 || config.DNS.Port < 1024) { // On UNIX, if we're running under a regular user, diff --git a/home/dns.go b/home/dns.go index 2d647f94..820b441a 100644 --- a/home/dns.go +++ b/home/dns.go @@ -172,12 +172,20 @@ func generateServerConfig() dnsforward.ServerConfig { Context.tls.WriteDiskConfig(&tlsConf) if tlsConf.Enabled { newconfig.TLSConfig = tlsConf.TLSConfig + if tlsConf.PortDNSOverTLS != 0 { newconfig.TLSListenAddr = &net.TCPAddr{ IP: net.ParseIP(config.DNS.BindHost), Port: tlsConf.PortDNSOverTLS, } } + + if tlsConf.PortDNSOverQUIC != 0 { + newconfig.QUICListenAddr = &net.UDPAddr{ + IP: net.ParseIP(config.DNS.BindHost), + Port: int(tlsConf.PortDNSOverQUIC), + } + } } newconfig.TLSv12Roots = Context.tlsRoots newconfig.TLSCiphers = Context.tlsCiphers @@ -225,6 +233,11 @@ func getDNSAddresses() []string { addr := fmt.Sprintf("tls://%s:%d", tlsConf.ServerName, tlsConf.PortDNSOverTLS) dnsAddresses = append(dnsAddresses, addr) } + + if tlsConf.PortDNSOverQUIC != 0 { + addr := fmt.Sprintf("quic://%s:%d", tlsConf.ServerName, tlsConf.PortDNSOverQUIC) + dnsAddresses = append(dnsAddresses, addr) + } } return dnsAddresses diff --git a/home/tls.go b/home/tls.go index 157cda2a..0b9e8f90 100644 --- a/home/tls.go +++ b/home/tls.go @@ -45,6 +45,7 @@ func tlsCreate(conf tlsConfigSettings) *TLSMod { ServerName: conf.ServerName, PortHTTPS: conf.PortHTTPS, PortDNSOverTLS: conf.PortDNSOverTLS, + PortDNSOverQUIC: conf.PortDNSOverQUIC, AllowUnencryptedDOH: conf.AllowUnencryptedDOH, }} } @@ -267,6 +268,7 @@ func (t *TLSMod) handleTLSConfigure(w http.ResponseWriter, r *http.Request) { t.conf.ForceHTTPS = data.ForceHTTPS t.conf.PortHTTPS = data.PortHTTPS t.conf.PortDNSOverTLS = data.PortDNSOverTLS + t.conf.PortDNSOverQUIC = data.PortDNSOverQUIC t.conf.CertificateChain = data.CertificateChain t.conf.CertificatePath = data.CertificatePath t.conf.CertificateChainData = data.CertificateChainData diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 57d63c70..7777c069 100644 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -1563,6 +1563,11 @@ components: format: int32 example: 853 description: DNS-over-TLS port. If 0, DOT will be disabled. + port_dns_over_quic: + type: integer + format: int32 + example: 784 + description: DNS-over-QUIC port. If 0, DOQ will be disabled. certificate_chain: type: string description: Base64 string with PEM-encoded certificates chain From 8dc010886867de62340d933df7edc31314234abc Mon Sep 17 00:00:00 2001 From: Artem Baskal Date: Sat, 5 Sep 2020 10:22:47 +0300 Subject: [PATCH 06/19] + client: Redesign query logs block/unblock buttons Close #2050 Squashed commit of the following: commit 3bc6a409034989b914306e1c33da274730ca623e Author: ArtemBaskal Date: Fri Sep 4 20:58:09 2020 +0300 Change dashboard block confirm message commit d4d47c3557e2166ee04db25a71b782bfbfe3b865 Merge: e8865827 fc43e2ac Author: ArtemBaskal Date: Fri Sep 4 14:56:34 2020 +0300 Merge branch 'master' into feature/2050 commit e8865827879955b1ef62c9ff85798d07bfa4627d Author: ArtemBaskal Date: Fri Sep 4 13:46:10 2020 +0300 Rename classname commit 648151c54e493c63622e014cb9cd1cb450f25478 Author: ArtemBaskal Date: Thu Sep 3 19:09:21 2020 +0300 Decrease arrow size commit 4feadab707c613d31225dfa9443a9a836db37ba1 Author: ArtemBaskal Date: Thu Sep 3 18:27:41 2020 +0300 Rename button class commit c3919d8ae8d1431657ce61afad2c20e5806f279a Author: ArtemBaskal Date: Thu Sep 3 10:35:15 2020 +0300 Review changes: extract variables commit 0ac809584c391e41a1749a844bc1075e05a92345 Author: ArtemBaskal Date: Thu Sep 3 10:13:57 2020 +0300 Display dashboard button on hover commit 1395287c2383e2248a2a5d39451403bd73141e55 Author: ArtemBaskal Date: Wed Sep 2 21:24:04 2020 +0300 Do not hide button on option open commit 947f254b7aea26f289b66b66fac46dba11ea3952 Author: ArtemBaskal Date: Wed Sep 2 21:20:19 2020 +0300 Add buttons for mobile screen commit df05697f87163a2b716d82653884e631f2fa6cf3 Author: ArtemBaskal Date: Wed Sep 2 20:18:20 2020 +0300 Change dashboard button styles commit 16655f2d6b0d79d1fa027ec2310bb0268fffaf6a Author: ArtemBaskal Date: Wed Sep 2 20:04:28 2020 +0300 Change button styles, rename button options commit 1ac22e875d8b26c16830bf6edb85dadcc19ff287 Author: ArtemBaskal Date: Wed Sep 2 19:30:16 2020 +0300 Review changes commit c590119875439d85927bdd334658e003bc1f0563 Author: ArtemBaskal Date: Wed Sep 2 17:58:08 2020 +0300 Remove default query logs form values commit 141329563417f5337f5659d5500f4cbe16d64bd2 Author: ArtemBaskal Date: Wed Sep 2 17:41:23 2020 +0300 Update blocking buttons options logic, fix button svg size commit 9e4f39aa6cb8e134d80d496b8a248b2fe6aceb99 Author: ArtemBaskal Date: Wed Sep 2 16:30:48 2020 +0300 Fix button position commit 8aabff7daccb87ae02c2302e62e296b3cfc17608 Merge: 415a0334 6b614295 Author: ArtemBaskal Date: Tue Sep 1 17:29:55 2020 +0300 Merge branch 'master' into feature/2050 commit 415a0334561733d92a0f7badd68101ef554dc689 Author: ArtemBaskal Date: Tue Sep 1 17:05:51 2020 +0300 Add blocking options commit bc6aed92b6e12f27c2604501275b53bb8159d5bc Merge: 0de4fb3a 40b74522 Author: ArtemBaskal Date: Tue Sep 1 15:49:06 2020 +0300 Merge branch 'feature/infinite_scroll_query_logs' into feature/2050 commit 40b745225112cf8d664220ed8f484b0aa16e997c Author: ArtemBaskal Date: Tue Sep 1 15:46:27 2020 +0300 Remove dynamic translation of toasts commit 0de4fb3a4cd785c6b52e860e204c6e13d356b178 Merge: 1ab14471 f08fa7b8 Author: ArtemBaskal Date: Tue Sep 1 15:07:30 2020 +0300 Merge branch 'feature/infinite_scroll_query_logs' into feature/2050 ... and 51 more commits --- client/src/__locales/en.json | 7 +- client/src/actions/index.js | 19 ++- client/src/components/App/index.css | 9 ++ client/src/components/Dashboard/Clients.js | 15 +-- client/src/components/Header/Header.css | 4 + .../src/components/Logs/Cells/ClientCell.js | 101 ++++++++++++--- .../src/components/Logs/Cells/IconTooltip.js | 16 ++- .../components/Logs/Cells/helpers/index.js | 19 +++ client/src/components/Logs/Cells/index.js | 42 ++++++- client/src/components/Logs/Logs.css | 115 +++++++++++++++--- client/src/components/Logs/index.js | 5 +- client/src/components/ui/Icons.js | 8 ++ client/src/components/ui/Tooltip.js | 7 +- client/src/helpers/helpers.js | 18 +++ 14 files changed, 327 insertions(+), 58 deletions(-) create mode 100644 client/src/components/Logs/Cells/helpers/index.js diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index e8e984e2..6cce0d91 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -194,6 +194,10 @@ "dns_test_not_ok_toast": "Server \"{{key}}\": could not be used, please check that you've written it correctly", "unblock": "Unblock", "block": "Block", + "disallow_this_client": "Disallow this client", + "allow_this_client": "Allow this client", + "block_for_this_client_only": "Block for this client only", + "unblock_for_this_client_only": "Unblock for this client only", "time_table_header": "Time", "date": "Date", "domain_name_table_header": "Domain name", @@ -569,5 +573,6 @@ "setup_config_to_enable_dhcp_server": "Setup config to enable DHCP server", "original_response": "Original response", "click_to_view_queries": "Click to view queries", - "port_53_faq_link": "Port 53 is often occupied by \"DNSStubListener\" or \"systemd-resolved\" services. Please read <0>this instruction on how to resolve this." + "port_53_faq_link": "Port 53 is often occupied by \"DNSStubListener\" or \"systemd-resolved\" services. Please read <0>this instruction on how to resolve this.", + "adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client." } diff --git a/client/src/actions/index.js b/client/src/actions/index.js index ff512883..d4018bb0 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -545,15 +545,17 @@ export const removeStaticLease = (config) => async (dispatch) => { export const removeToast = createAction('REMOVE_TOAST'); -export const toggleBlocking = (type, domain) => async (dispatch, getState) => { +export const toggleBlocking = ( + type, domain, baseRule, baseUnblocking, +) => async (dispatch, getState) => { + const baseBlockingRule = baseRule || `||${domain}^$important`; + const baseUnblockingRule = baseUnblocking || `@@${baseBlockingRule}`; const { userRules } = getState().filtering; const lineEnding = !endsWith(userRules, '\n') ? '\n' : ''; - const baseRule = `||${domain}^$important`; - const baseUnblocking = `@@${baseRule}`; - const blockingRule = type === BLOCK_ACTIONS.BLOCK ? baseUnblocking : baseRule; - const unblockingRule = type === BLOCK_ACTIONS.BLOCK ? baseRule : baseUnblocking; + const blockingRule = type === BLOCK_ACTIONS.BLOCK ? baseUnblockingRule : baseBlockingRule; + const unblockingRule = type === BLOCK_ACTIONS.BLOCK ? baseBlockingRule : baseUnblockingRule; const preparedBlockingRule = new RegExp(`(^|\n)${escapeRegExp(blockingRule)}($|\n)`); const preparedUnblockingRule = new RegExp(`(^|\n)${escapeRegExp(unblockingRule)}($|\n)`); @@ -576,3 +578,10 @@ export const toggleBlocking = (type, domain) => async (dispatch, getState) => { dispatch(getFilteringStatus()); }; + +export const toggleBlockingForClient = (type, domain, client) => { + const baseRule = `||${domain}^$client='${client.replace(/'/g, '/\'')}'`; + const baseUnblocking = `@@${baseRule}`; + + return toggleBlocking(type, domain, baseRule, baseUnblocking); +}; diff --git a/client/src/components/App/index.css b/client/src/components/App/index.css index 091a6612..e2b0304d 100644 --- a/client/src/components/App/index.css +++ b/client/src/components/App/index.css @@ -66,3 +66,12 @@ body { .select--no-warning { margin-bottom: 1.375rem; } + +.button-action { + visibility: hidden; +} + +.logs__row:hover .button-action, +.button-action--active { + visibility: visible; +} diff --git a/client/src/components/Dashboard/Clients.js b/client/src/components/Dashboard/Clients.js index 24b278f4..3c163035 100644 --- a/client/src/components/Dashboard/Clients.js +++ b/client/src/components/Dashboard/Clients.js @@ -51,15 +51,16 @@ const renderBlockingButton = (ip) => { const type = isNotFound ? BLOCK_ACTIONS.BLOCK : BLOCK_ACTIONS.UNBLOCK; const text = type; - const className = classNames('btn btn-sm', { - 'btn-outline-danger': isNotFound, - 'btn-outline-secondary': !isNotFound, + const buttonClass = classNames('button-action button-action--main', { + 'button-action--unblock': !isNotFound, }); const toggleClientStatus = (type, ip) => { - const confirmMessage = type === BLOCK_ACTIONS.BLOCK ? 'client_confirm_block' : 'client_confirm_unblock'; + const confirmMessage = type === BLOCK_ACTIONS.BLOCK + ? `${t('adg_will_drop_dns_queries')} ${t('client_confirm_block', { ip })}` + : t('client_confirm_unblock', { ip }); - if (window.confirm(t(confirmMessage, { ip }))) { + if (window.confirm(confirmMessage)) { dispatch(toggleClientBlock(type, ip)); } }; @@ -69,7 +70,7 @@ const renderBlockingButton = (ip) => { return
; + const getOptions = (optionToActionMap) => { + const options = Object.entries(optionToActionMap); + if (options.length === 0) { + return null; + } + return <>{options + .map(([name, onClick]) =>
{t(name)} +
)}; + }; + + const content = getOptions(BUTTON_OPTIONS_TO_ACTION_MAP); + + const buttonClass = classNames('button-action button-action--main', { + 'button-action--unblock': isFiltered, + 'button-action--with-options': content, + 'button-action--active': isOptionsOpened, + }); + + const buttonArrowClass = classNames('button-action button-action--arrow', { + 'button-action--unblock': isFiltered, + 'button-action--active': isOptionsOpened, + }); + + const containerClass = classNames('button-action__container', { + 'button-action__container--detailed': isDetailed, + }); + + return
+ + {content && } +
; }; return
@@ -81,9 +148,7 @@ const ClientCell = ({
{isDetailed && name && !whoisAvailable &&
- {name} -
} + title={name}>{name}
}
{renderBlockingButton(isFiltered, domain)} ; diff --git a/client/src/components/Logs/Cells/IconTooltip.js b/client/src/components/Logs/Cells/IconTooltip.js index 5b9cc2cb..8bb3d624 100644 --- a/client/src/components/Logs/Cells/IconTooltip.js +++ b/client/src/components/Logs/Cells/IconTooltip.js @@ -6,17 +6,21 @@ import { processContent } from '../../../helpers/helpers'; import Tooltip from '../../ui/Tooltip'; import 'react-popper-tooltip/dist/styles.css'; import './IconTooltip.css'; +import { SHOW_TOOLTIP_DELAY } from '../../../helpers/constants'; const IconTooltip = ({ className, contentItemClass, columnClass, + triggerClass, canShowTooltip = true, xlinkHref, title, placement, tooltipClass, content, + trigger, + onVisibilityChange, renderContent = content ? React.Children.map( processContent(content), (item, idx) =>
@@ -36,6 +40,10 @@ const IconTooltip = ({ className={tooltipClassName} content={tooltipContent} placement={placement} + triggerClass={triggerClass} + trigger={trigger} + onVisibilityChange={onVisibilityChange} + delayShow={trigger === 'click' ? 0 : SHOW_TOOLTIP_DELAY} > {xlinkHref && @@ -45,6 +53,8 @@ const IconTooltip = ({ IconTooltip.propTypes = { className: PropTypes.string, + trigger: PropTypes.string, + triggerClass: PropTypes.string, contentItemClass: PropTypes.string, columnClass: PropTypes.string, tooltipClass: PropTypes.string, @@ -52,11 +62,9 @@ IconTooltip.propTypes = { placement: PropTypes.string, canShowTooltip: PropTypes.bool, xlinkHref: PropTypes.string, - content: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.array, - ]), + content: PropTypes.node, renderContent: PropTypes.arrayOf(PropTypes.element), + onVisibilityChange: PropTypes.func, }; export default IconTooltip; diff --git a/client/src/components/Logs/Cells/helpers/index.js b/client/src/components/Logs/Cells/helpers/index.js new file mode 100644 index 00000000..61e7ff5c --- /dev/null +++ b/client/src/components/Logs/Cells/helpers/index.js @@ -0,0 +1,19 @@ +import { getIpMatchListStatus } from '../../../../helpers/helpers'; +import { BLOCK_ACTIONS, IP_MATCH_LIST_STATUS } from '../../../../helpers/constants'; + +export const BUTTON_PREFIX = 'btn_'; + +export const getBlockClientInfo = (client, disallowed_clients) => { + const ipMatchListStatus = getIpMatchListStatus(client, disallowed_clients); + + const isNotFound = ipMatchListStatus === IP_MATCH_LIST_STATUS.NOT_FOUND; + const type = isNotFound ? BLOCK_ACTIONS.BLOCK : BLOCK_ACTIONS.UNBLOCK; + + const confirmMessage = isNotFound ? 'client_confirm_block' : 'client_confirm_unblock'; + const buttonKey = isNotFound ? 'disallow_this_client' : 'allow_this_client'; + return { + confirmMessage, + buttonKey, + type, + }; +}; diff --git a/client/src/components/Logs/Cells/index.js b/client/src/components/Logs/Cells/index.js index c2d7968b..8a0fced3 100644 --- a/client/src/components/Logs/Cells/index.js +++ b/client/src/components/Logs/Cells/index.js @@ -9,6 +9,7 @@ import { formatDateTime, formatElapsedMs, formatTime, + getBlockingClientName, getFilterName, processContent, } from '../../../helpers/helpers'; @@ -22,12 +23,14 @@ import { SCHEME_TO_PROTOCOL_MAP, } from '../../../helpers/constants'; import { getSourceData } from '../../../helpers/trackers/trackers'; -import { toggleBlocking } from '../../../actions'; +import { toggleBlocking, toggleBlockingForClient } from '../../../actions'; import DateCell from './DateCell'; import DomainCell from './DomainCell'; import ResponseCell from './ResponseCell'; import ClientCell from './ClientCell'; import '../Logs.css'; +import { toggleClientBlock } from '../../../actions/access'; +import { getBlockClientInfo, BUTTON_PREFIX } from './helpers'; const Row = memo(({ style, @@ -45,6 +48,13 @@ const Row = memo(({ const whitelistFilters = useSelector((state) => state.filtering.whitelistFilters, shallowEqual); const autoClients = useSelector((state) => state.dashboard.autoClients, shallowEqual); + const disallowed_clients = useSelector( + (state) => state.access.disallowed_clients, + shallowEqual, + ); + + const clients = useSelector((state) => state.dashboard.clients); + const onClick = () => { if (!isSmallScreen) { return; } const { @@ -98,6 +108,26 @@ const Row = memo(({ const filter = getFilterName(filters, whitelistFilters, filterId); + const { + confirmMessage, + buttonKey: blockingClientKey, + type: blockType, + } = getBlockClientInfo(client, disallowed_clients); + + const blockingForClientKey = isFiltered ? 'unblock_for_this_client_only' : 'block_for_this_client_only'; + const clientNameBlockingFor = getBlockingClientName(clients, client); + + const onBlockingForClientClick = () => { + dispatch(toggleBlockingForClient(buttonType, domain, clientNameBlockingFor)); + }; + + const onBlockingClientClick = () => { + const message = `${blockType === BLOCK_ACTIONS.BLOCK ? t('adg_will_drop_dns_queries') : ''} ${t(confirmMessage, { ip: client })}`; + if (window.confirm(message)) { + dispatch(toggleClientBlock(blockType, client)); + } + }; + const detailedData = { time_table_header: formatTime(time, LONG_TIME_FORMAT), date: formatDateTime(time, DEFAULT_SHORT_DATE_FORMAT_OPTIONS), @@ -132,10 +162,12 @@ const Row = memo(({ source_label: source, validated_with_dnssec: dnssec_enabled ? Boolean(answer_dnssec) : false, original_response: originalResponse?.join('\n'), - [buttonType]:
{t(buttonType)}
, + [BUTTON_PREFIX + buttonType]:
{t(buttonType)}
, + [BUTTON_PREFIX + blockingForClientKey]:
{t(blockingForClientKey)}
, + [BUTTON_PREFIX + blockingClientKey]:
{t(blockingClientKey)}
, }; setDetailedDataCurrent(processContent(detailedData)); diff --git a/client/src/components/Logs/Logs.css b/client/src/components/Logs/Logs.css index 857fd466..fd088b79 100644 --- a/client/src/components/Logs/Logs.css +++ b/client/src/components/Logs/Logs.css @@ -10,9 +10,20 @@ --size-client: 123; --gray-216: rgba(216, 216, 216, 0.23); --gray-4d: #4D4D4D; + --gray-f3: #F3F3F3; --gray-8: #888; --danger: #DF3812; --white80: rgba(255, 255, 255, 0.8); + + --btn-block: #C23814; + --btn-block-disabled: #E3B3A6; + --btn-block-active: #A62200; + + --btn-unblock: #888888; + --btn-unblock-disabled: #D8D8D8; + --btn-unblock-active: #4D4D4D; + + --option-border-radius: 4px; } .logs__text { @@ -191,6 +202,7 @@ width: 7.6875rem; flex: var(--size-client) 0 auto; padding-right: 0; + position: relative; } .logs__cell--header__container > .logs__cell--header__item { @@ -202,12 +214,95 @@ padding-right: 0; } -.logs__cell--block-button { - max-height: 1.75rem; - position: relative; - left: 10%; - top: 40%; - visibility: hidden; +.button-action__container { + display: flex; + position: absolute; + right: 0; + bottom: 0.5rem; + height: 1.6rem; +} + +.button-action__container--detailed { + bottom: 1.3rem; +} + +.button-action { + outline: 0 !important; + background: var(--btn-block); + border-radius: var(--option-border-radius); + font-size: 0.8rem; + color: var(--white); + letter-spacing: 0; + text-align: center; + line-height: 28px; + border: 0; +} + +.button-action--unblock { + background: var(--btn-unblock); +} + +.button-action--main { + padding: 0 1rem; + display: flex; + align-items: center; +} + +.button-action--with-options { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.button-action--arrow { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-left: 1px solid var(--white); + width: 1.5625rem; + padding: 0; + display: flex; + align-items: center; + justify-content: center; +} + +.button-action:hover { + cursor: pointer; +} + +.button-action--arrow .button-action--icon { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + +.button-action:active { + background: var(--btn-block-active); +} + +.button-action--unblock:active { + background: var(--btn-unblock-active); +} + +.button-action:disabled { + background: var(--btn-block-disabled); + cursor: default; +} + +.button-action--unblock:disabled { + background: var(--btn-unblock-disabled); +} + +.button-action--arrow-option:hover { + cursor: pointer; + background: var(--gray-f3); + overflow: hidden; +} + +.button-action--arrow-option-container { + overflow: visible; + transform-origin: left; + padding: 1rem 0; } .logs__row { @@ -222,14 +317,6 @@ border-bottom: 2px solid var(--gray-216); } -.logs__table .logs__row:hover .logs__cell--block-button { - visibility: visible; -} - -.logs__table .logs__row .logs__cell--block-button:disabled { - background-color: var(--white) !important; -} - /* QUERY_STATUS_COLORS */ .logs__row--blue { background-color: var(--blue); diff --git a/client/src/components/Logs/index.js b/client/src/components/Logs/index.js index 13fa697c..bcc9a94d 100644 --- a/client/src/components/Logs/index.js +++ b/client/src/components/Logs/index.js @@ -23,15 +23,16 @@ import { } from '../../actions/queryLogs'; import InfiniteTable from './InfiniteTable'; import './Logs.css'; +import { BUTTON_PREFIX } from './Cells/helpers'; -const processContent = (data, buttonType) => Object.entries(data) +const processContent = (data) => Object.entries(data) .map(([key, value]) => { if (!value) { return null; } const isTitle = value === 'title'; - const isButton = key === buttonType; + const isButton = key.startsWith(BUTTON_PREFIX); const isBoolean = typeof value === 'boolean'; const isHidden = isBoolean && value === false; diff --git a/client/src/components/ui/Icons.js b/client/src/components/ui/Icons.js index f29bcc21..3851ff01 100644 --- a/client/src/components/ui/Icons.js +++ b/client/src/components/ui/Icons.js @@ -344,6 +344,14 @@ const Icons = () => ( + + + + + + + ); diff --git a/client/src/components/ui/Tooltip.js b/client/src/components/ui/Tooltip.js index 9f34b3fe..87b353de 100644 --- a/client/src/components/ui/Tooltip.js +++ b/client/src/components/ui/Tooltip.js @@ -20,6 +20,7 @@ const Tooltip = ({ trigger = 'hover', delayShow = SHOW_TOOLTIP_DELAY, delayHide = HIDE_TOOLTIP_DELAY, + onVisibilityChange, }) => { const { t } = useTranslation(); const touchEventsAvailable = 'ontouchstart' in window; @@ -73,6 +74,7 @@ const Tooltip = ({ delayHide={delayHideValue} delayShow={delayShowValue} tooltip={renderTooltip} + onVisibilityChange={onVisibilityChange} > {renderTrigger} @@ -90,10 +92,11 @@ Tooltip.propTypes = { ).isRequired, placement: propTypes.string, trigger: propTypes.string, - delayHide: propTypes.string, - delayShow: propTypes.string, + delayHide: propTypes.number, + delayShow: propTypes.number, className: propTypes.string, triggerClass: propTypes.string, + onVisibilityChange: propTypes.func, }; export default Tooltip; diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js index fa3a5046..bafd230e 100644 --- a/client/src/helpers/helpers.js +++ b/client/src/helpers/helpers.js @@ -836,3 +836,21 @@ export const isScrolledIntoView = (el) => { return elemTop < window.innerHeight && elemBottom >= 0; }; + +/** + * If this is a manually created client, return its name. + * If this is a "runtime" client, return it's IP address. + * @param clients {Array.} + * @param ip {string} + * @returns {string} + */ +export const getBlockingClientName = (clients, ip) => { + for (let i = 0; i < clients.length; i += 1) { + const client = clients[i]; + + if (client.ids.includes(ip)) { + return client.name; + } + } + return ip; +}; From 15a82233f3dc8b5307e3edef2214f98ab408de64 Mon Sep 17 00:00:00 2001 From: ArtemBaskal Date: Mon, 7 Sep 2020 10:36:17 +0300 Subject: [PATCH 07/19] - client: Fix whois cell styles --- client/src/components/Logs/Logs.css | 25 +++++++++++++++++++ .../components/Settings/Clients/whoisCell.js | 2 +- .../src/helpers/renderFormattedClientCell.js | 2 +- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/client/src/components/Logs/Logs.css b/client/src/components/Logs/Logs.css index fd088b79..b230ab8b 100644 --- a/client/src/components/Logs/Logs.css +++ b/client/src/components/Logs/Logs.css @@ -388,3 +388,28 @@ .logs__table .loading:before { min-height: 100%; } + +.logs__whois { + display: inline; + font-size: 12px; + white-space: nowrap; +} + +.logs__whois::after { + content: "|"; + padding: 0 5px; + opacity: 0.3; +} + +.logs__whois:last-child::after { + content: ""; +} + +.logs__whois-icon.icons { + position: relative; + top: -2px; + width: 12px; + height: 12px; + margin-right: 1px; + opacity: 0.5; +} diff --git a/client/src/components/Settings/Clients/whoisCell.js b/client/src/components/Settings/Clients/whoisCell.js index 94afd6cc..1a8b0484 100644 --- a/client/src/components/Settings/Clients/whoisCell.js +++ b/client/src/components/Settings/Clients/whoisCell.js @@ -14,7 +14,7 @@ const getFormattedWhois = (value, t) => {
{icon && ( - +   diff --git a/client/src/helpers/renderFormattedClientCell.js b/client/src/helpers/renderFormattedClientCell.js index fa705496..d677c4ca 100644 --- a/client/src/helpers/renderFormattedClientCell.js +++ b/client/src/helpers/renderFormattedClientCell.js @@ -9,7 +9,7 @@ const getFormattedWhois = (whois) => { .map((key) => { const icon = WHOIS_ICONS[key]; return ( - + {icon && ( <> From 03506df25d5c6af6daf1ba19300d2697ad241bda Mon Sep 17 00:00:00 2001 From: David Sheets Date: Mon, 7 Sep 2020 09:10:56 +0100 Subject: [PATCH 08/19] cli: factor options struct and parsing into home/options.go --- home/home.go | 109 +++--------------- home/options.go | 255 +++++++++++++++++++++++++++++++++++++++++++ home/options_test.go | 171 +++++++++++++++++++++++++++++ 3 files changed, 439 insertions(+), 96 deletions(-) create mode 100644 home/options.go create mode 100644 home/options_test.go diff --git a/home/home.go b/home/home.go index b9d7a760..806c59e2 100644 --- a/home/home.go +++ b/home/home.go @@ -526,108 +526,25 @@ func cleanupAlways() { log.Info("Stopped") } -// command-line arguments -type options struct { - verbose bool // is verbose logging enabled - configFilename string // path to the config file - workDir string // path to the working directory where we will store the filters data and the querylog - bindHost string // host address to bind HTTP server on - bindPort int // port to serve HTTP pages on - logFile string // Path to the log file. If empty, write to stdout. If "syslog", writes to syslog - pidFile string // File name to save PID to - checkConfig bool // Check configuration and exit - disableUpdate bool // If set, don't check for updates - - // service control action (see service.ControlAction array + "status" command) - serviceControlAction string - - // runningAsService flag is set to true when options are passed from the service runner - runningAsService bool - - glinetMode bool // Activate GL-Inet mode +func exitWithError() { + os.Exit(64) } // loadOptions reads command line arguments and initializes configuration func loadOptions() options { - o := options{} + o, f, err := parse(os.Args[0], os.Args[1:]) - var printHelp func() - var opts = []struct { - longName string - shortName string - description string - callbackWithValue func(value string) - callbackNoValue func() - }{ - {"config", "c", "Path to the config file", func(value string) { o.configFilename = value }, nil}, - {"work-dir", "w", "Path to the working directory", func(value string) { o.workDir = value }, nil}, - {"host", "h", "Host address to bind HTTP server on", func(value string) { o.bindHost = value }, nil}, - {"port", "p", "Port to serve HTTP pages on", func(value string) { - v, err := strconv.Atoi(value) - if err != nil { - panic("Got port that is not a number") - } - o.bindPort = v - }, nil}, - {"service", "s", "Service control action: status, install, uninstall, start, stop, restart, reload (configuration)", func(value string) { - o.serviceControlAction = value - }, nil}, - {"logfile", "l", "Path to log file. If empty: write to stdout; if 'syslog': write to system log", func(value string) { - o.logFile = value - }, nil}, - {"pidfile", "", "Path to a file where PID is stored", func(value string) { o.pidFile = value }, nil}, - {"check-config", "", "Check configuration and exit", nil, func() { o.checkConfig = true }}, - {"no-check-update", "", "Don't check for updates", nil, func() { o.disableUpdate = true }}, - {"verbose", "v", "Enable verbose output", nil, func() { o.verbose = true }}, - {"glinet", "", "Run in GL-Inet compatibility mode", nil, func() { o.glinetMode = true }}, - {"version", "", "Show the version and exit", nil, func() { - fmt.Println(version()) + if err != nil { + log.Error(err.Error()) + _ = printHelp(os.Args[0]) + exitWithError() + } else if f != nil { + err = f() + if err != nil { + log.Error(err.Error()) + exitWithError() + } else { os.Exit(0) - }}, - {"help", "", "Print this help", nil, func() { - printHelp() - os.Exit(64) - }}, - } - printHelp = func() { - fmt.Printf("Usage:\n\n") - fmt.Printf("%s [options]\n\n", os.Args[0]) - fmt.Printf("Options:\n") - for _, opt := range opts { - val := "" - if opt.callbackWithValue != nil { - val = " VALUE" - } - if opt.shortName != "" { - fmt.Printf(" -%s, %-30s %s\n", opt.shortName, "--"+opt.longName+val, opt.description) - } else { - fmt.Printf(" %-34s %s\n", "--"+opt.longName+val, opt.description) - } - } - } - for i := 1; i < len(os.Args); i++ { - v := os.Args[i] - knownParam := false - for _, opt := range opts { - if v == "--"+opt.longName || (opt.shortName != "" && v == "-"+opt.shortName) { - if opt.callbackWithValue != nil { - if i+1 >= len(os.Args) { - log.Error("Got %s without argument\n", v) - os.Exit(64) - } - i++ - opt.callbackWithValue(os.Args[i]) - } else if opt.callbackNoValue != nil { - opt.callbackNoValue() - } - knownParam = true - break - } - } - if !knownParam { - log.Error("unknown option %v\n", v) - printHelp() - os.Exit(64) } } diff --git a/home/options.go b/home/options.go new file mode 100644 index 00000000..ec789d4f --- /dev/null +++ b/home/options.go @@ -0,0 +1,255 @@ +package home + +import ( + "fmt" + "os" + "strconv" +) + +// options passed from command-line arguments +type options struct { + verbose bool // is verbose logging enabled + configFilename string // path to the config file + workDir string // path to the working directory where we will store the filters data and the querylog + bindHost string // host address to bind HTTP server on + bindPort int // port to serve HTTP pages on + logFile string // Path to the log file. If empty, write to stdout. If "syslog", writes to syslog + pidFile string // File name to save PID to + checkConfig bool // Check configuration and exit + disableUpdate bool // If set, don't check for updates + + // service control action (see service.ControlAction array + "status" command) + serviceControlAction string + + // runningAsService flag is set to true when options are passed from the service runner + runningAsService bool + + glinetMode bool // Activate GL-Inet mode +} + +// functions used for their side-effects +type effect func() error + +type arg struct { + description string // a short, English description of the argument + longName string // the name of the argument used after '--' + shortName string // the name of the argument used after '-' + + // only one of updateWithValue, updateNoValue, and effect should be present + + updateWithValue func(o options, v string) (options, error) // the mutator for arguments with parameters + updateNoValue func(o options) (options, error) // the mutator for arguments without parameters + effect func(o options, exec string) (f effect, err error) // the side-effect closure generator +} + +var args []arg + +var configArg = arg{ + "Path to the config file", + "config", "c", + func(o options, v string) (options, error) { o.configFilename = v; return o, nil }, + nil, + nil, +} + +var workDirArg = arg{ + "Path to the working directory", + "work-dir", "w", + func(o options, v string) (options, error) { o.workDir = v; return o, nil }, nil, nil, +} + +var hostArg = arg{ + "Host address to bind HTTP server on", + "host", "h", + func(o options, v string) (options, error) { o.bindHost = v; return o, nil }, nil, nil, +} + +var portArg = arg{ + "Port to serve HTTP pages on", + "port", "p", + func(o options, v string) (options, error) { + var err error + var p int + minPort, maxPort := 0, 1<<16-1 + if p, err = strconv.Atoi(v); err != nil { + err = fmt.Errorf("port '%s' is not a number", v) + } else if p < minPort || p > maxPort { + err = fmt.Errorf("port %d not in range %d - %d", p, minPort, maxPort) + } else { + o.bindPort = p + } + return o, err + }, nil, nil, +} + +var serviceArg = arg{ + "Service control action: status, install, uninstall, start, stop, restart, reload (configuration)", + "service", "s", + func(o options, v string) (options, error) { + o.serviceControlAction = v + return o, nil + }, nil, nil, +} + +var logfileArg = arg{ + "Path to log file. If empty: write to stdout; if 'syslog': write to system log", + "logfile", "l", + func(o options, v string) (options, error) { o.logFile = v; return o, nil }, nil, nil, +} + +var pidfileArg = arg{ + "Path to a file where PID is stored", + "pidfile", "", + func(o options, v string) (options, error) { o.pidFile = v; return o, nil }, nil, nil, +} + +var checkConfigArg = arg{ + "Check configuration and exit", + "check-config", "", + nil, func(o options) (options, error) { o.checkConfig = true; return o, nil }, nil, +} + +var noCheckUpdateArg = arg{ + "Don't check for updates", + "no-check-update", "", + nil, func(o options) (options, error) { o.disableUpdate = true; return o, nil }, nil, +} + +var verboseArg = arg{ + "Enable verbose output", + "verbose", "v", + nil, func(o options) (options, error) { o.verbose = true; return o, nil }, nil, +} + +var glinetArg = arg{ + "Run in GL-Inet compatibility mode", + "glinet", "", + nil, func(o options) (options, error) { o.glinetMode = true; return o, nil }, nil, +} + +var versionArg = arg{ + "Show the version and exit", + "version", "", + nil, nil, func(o options, exec string) (effect, error) { + return func() error { fmt.Println(version()); os.Exit(0); return nil }, nil + }, +} + +var helpArg = arg{ + "Print this help", + "help", "", + nil, nil, func(o options, exec string) (effect, error) { + return func() error { _ = printHelp(exec); os.Exit(64); return nil }, nil + }, +} + +func init() { + args = []arg{ + configArg, + workDirArg, + hostArg, + portArg, + serviceArg, + logfileArg, + pidfileArg, + checkConfigArg, + noCheckUpdateArg, + verboseArg, + glinetArg, + versionArg, + helpArg, + } +} + +func getUsageLines(exec string, args []arg) []string { + usage := []string{ + "Usage:", + "", + fmt.Sprintf("%s [options]", exec), + "", + "Options:", + } + for _, arg := range args { + val := "" + if arg.updateWithValue != nil { + val = " VALUE" + } + if arg.shortName != "" { + usage = append(usage, fmt.Sprintf(" -%s, %-30s %s", + arg.shortName, + "--"+arg.longName+val, + arg.description)) + } else { + usage = append(usage, fmt.Sprintf(" %-34s %s", + "--"+arg.longName+val, + arg.description)) + } + } + return usage +} + +func printHelp(exec string) error { + for _, line := range getUsageLines(exec, args) { + _, err := fmt.Println(line) + if err != nil { + return err + } + } + return nil +} + +func argMatches(a arg, v string) bool { + return v == "--"+a.longName || (a.shortName != "" && v == "-"+a.shortName) +} + +func parse(exec string, ss []string) (o options, f effect, err error) { + for i := 0; i < len(ss); i++ { + v := ss[i] + knownParam := false + for _, arg := range args { + if argMatches(arg, v) { + if arg.updateWithValue != nil { + if i+1 >= len(ss) { + return o, f, fmt.Errorf("got %s without argument", v) + } + i++ + o, err = arg.updateWithValue(o, ss[i]) + if err != nil { + return + } + } else if arg.updateNoValue != nil { + o, err = arg.updateNoValue(o) + if err != nil { + return + } + } else if arg.effect != nil { + var eff effect + eff, err = arg.effect(o, exec) + if err != nil { + return + } + if eff != nil { + prevf := f + f = func() error { + var err error + if prevf != nil { + err = prevf() + } + if err == nil { + err = eff() + } + return err + } + } + } + knownParam = true + break + } + } + if !knownParam { + return o, f, fmt.Errorf("unknown option %v", v) + } + } + + return +} diff --git a/home/options_test.go b/home/options_test.go new file mode 100644 index 00000000..750f3ce2 --- /dev/null +++ b/home/options_test.go @@ -0,0 +1,171 @@ +package home + +import ( + "fmt" + "testing" +) + +func testParseOk(t *testing.T, ss ...string) options { + o, _, err := parse("", ss) + if err != nil { + t.Fatal(err.Error()) + } + return o +} + +func testParseErr(t *testing.T, descr string, ss ...string) { + _, _, err := parse("", ss) + if err == nil { + t.Fatalf("expected an error because %s but no error returned", descr) + } +} + +func testParseParamMissing(t *testing.T, param string) { + testParseErr(t, fmt.Sprintf("%s parameter missing", param), param) +} + +func TestParseVerbose(t *testing.T) { + if testParseOk(t).verbose { + t.Fatal("empty is not verbose") + } + if !testParseOk(t, "-v").verbose { + t.Fatal("-v is verbose") + } + if !testParseOk(t, "--verbose").verbose { + t.Fatal("--verbose is verbose") + } +} + +func TestParseConfigFilename(t *testing.T) { + if testParseOk(t).configFilename != "" { + t.Fatal("empty is no config filename") + } + if testParseOk(t, "-c", "path").configFilename != "path" { + t.Fatal("-c is config filename") + } + testParseParamMissing(t, "-c") + if testParseOk(t, "--config", "path").configFilename != "path" { + t.Fatal("--configFilename is config filename") + } + testParseParamMissing(t, "--config") +} + +func TestParseWorkDir(t *testing.T) { + if testParseOk(t).workDir != "" { + t.Fatal("empty is no work dir") + } + if testParseOk(t, "-w", "path").workDir != "path" { + t.Fatal("-w is work dir") + } + testParseParamMissing(t, "-w") + if testParseOk(t, "--work-dir", "path").workDir != "path" { + t.Fatal("--work-dir is work dir") + } + testParseParamMissing(t, "--work-dir") +} + +func TestParseBindHost(t *testing.T) { + if testParseOk(t).bindHost != "" { + t.Fatal("empty is no host") + } + if testParseOk(t, "-h", "addr").bindHost != "addr" { + t.Fatal("-h is host") + } + testParseParamMissing(t, "-h") + if testParseOk(t, "--host", "addr").bindHost != "addr" { + t.Fatal("--host is host") + } + testParseParamMissing(t, "--host") +} + +func TestParseBindPort(t *testing.T) { + if testParseOk(t).bindPort != 0 { + t.Fatal("empty is port 0") + } + if testParseOk(t, "-p", "65535").bindPort != 65535 { + t.Fatal("-p is port") + } + testParseParamMissing(t, "-p") + if testParseOk(t, "--port", "65535").bindPort != 65535 { + t.Fatal("--port is port") + } + testParseParamMissing(t, "--port") +} + +func TestParseBindPortBad(t *testing.T) { + testParseErr(t, "not an int", "-p", "x") + testParseErr(t, "hex not supported", "-p", "0x100") + testParseErr(t, "port negative", "-p", "-1") + testParseErr(t, "port too high", "-p", "65536") + testParseErr(t, "port too high", "-p", "4294967297") // 2^32 + 1 + testParseErr(t, "port too high", "-p", "18446744073709551617") // 2^64 + 1 +} + +func TestParseLogfile(t *testing.T) { + if testParseOk(t).logFile != "" { + t.Fatal("empty is no log file") + } + if testParseOk(t, "-l", "path").logFile != "path" { + t.Fatal("-l is log file") + } + if testParseOk(t, "--logfile", "path").logFile != "path" { + t.Fatal("--logfile is log file") + } +} + +func TestParsePidfile(t *testing.T) { + if testParseOk(t).pidFile != "" { + t.Fatal("empty is no pid file") + } + if testParseOk(t, "--pidfile", "path").pidFile != "path" { + t.Fatal("--pidfile is pid file") + } +} + +func TestParseCheckConfig(t *testing.T) { + if testParseOk(t).checkConfig { + t.Fatal("empty is not check config") + } + if !testParseOk(t, "--check-config").checkConfig { + t.Fatal("--check-config is check config") + } +} + +func TestParseDisableUpdate(t *testing.T) { + if testParseOk(t).disableUpdate { + t.Fatal("empty is not disable update") + } + if !testParseOk(t, "--no-check-update").disableUpdate { + t.Fatal("--no-check-update is disable update") + } +} + +func TestParseService(t *testing.T) { + if testParseOk(t).serviceControlAction != "" { + t.Fatal("empty is no service command") + } + if testParseOk(t, "-s", "command").serviceControlAction != "command" { + t.Fatal("-s is service command") + } + if testParseOk(t, "--service", "command").serviceControlAction != "command" { + t.Fatal("--service is service command") + } +} + +func TestParseGLInet(t *testing.T) { + if testParseOk(t).glinetMode { + t.Fatal("empty is not GL-Inet mode") + } + if !testParseOk(t, "--glinet").glinetMode { + t.Fatal("--glinet is GL-Inet mode") + } +} + +func TestParseUnknown(t *testing.T) { + testParseErr(t, "unknown word", "x") + testParseErr(t, "unknown short", "-x") + testParseErr(t, "unknown long", "--x") + testParseErr(t, "unknown triple", "---x") + testParseErr(t, "unknown plus", "+x") + testParseErr(t, "unknown dash", "-") +} From d3428ca46c9d68b4d9d6d1967fbe128b7799dac7 Mon Sep 17 00:00:00 2001 From: David Sheets Date: Mon, 7 Sep 2020 09:53:16 +0100 Subject: [PATCH 09/19] home/options: add options -> args serialization --- home/options.go | 58 ++++++++++++++++++++++++++++++++++++++ home/options_test.go | 66 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/home/options.go b/home/options.go index ec789d4f..90d356e8 100644 --- a/home/options.go +++ b/home/options.go @@ -40,6 +40,33 @@ type arg struct { updateWithValue func(o options, v string) (options, error) // the mutator for arguments with parameters updateNoValue func(o options) (options, error) // the mutator for arguments without parameters effect func(o options, exec string) (f effect, err error) // the side-effect closure generator + + serialize func(o options) []string // the re-serialization function back to arguments (return nil for omit) +} + +// {type}SliceOrNil functions check their parameter of type {type} +// against its zero value and return nil if the parameter value is +// zero otherwise they return a string slice of the parameter + +func stringSliceOrNil(s string) []string { + if s == "" { + return nil + } + return []string{s} +} + +func intSliceOrNil(i int) []string { + if i == 0 { + return nil + } + return []string{strconv.Itoa(i)} +} + +func boolSliceOrNil(b bool) []string { + if b { + return []string{} + } + return nil } var args []arg @@ -50,18 +77,21 @@ var configArg = arg{ func(o options, v string) (options, error) { o.configFilename = v; return o, nil }, nil, nil, + func(o options) []string { return stringSliceOrNil(o.configFilename) }, } var workDirArg = arg{ "Path to the working directory", "work-dir", "w", func(o options, v string) (options, error) { o.workDir = v; return o, nil }, nil, nil, + func(o options) []string { return stringSliceOrNil(o.workDir) }, } var hostArg = arg{ "Host address to bind HTTP server on", "host", "h", func(o options, v string) (options, error) { o.bindHost = v; return o, nil }, nil, nil, + func(o options) []string { return stringSliceOrNil(o.bindHost) }, } var portArg = arg{ @@ -80,6 +110,7 @@ var portArg = arg{ } return o, err }, nil, nil, + func(o options) []string { return intSliceOrNil(o.bindPort) }, } var serviceArg = arg{ @@ -89,42 +120,49 @@ var serviceArg = arg{ o.serviceControlAction = v return o, nil }, nil, nil, + func(o options) []string { return stringSliceOrNil(o.serviceControlAction) }, } var logfileArg = arg{ "Path to log file. If empty: write to stdout; if 'syslog': write to system log", "logfile", "l", func(o options, v string) (options, error) { o.logFile = v; return o, nil }, nil, nil, + func(o options) []string { return stringSliceOrNil(o.logFile) }, } var pidfileArg = arg{ "Path to a file where PID is stored", "pidfile", "", func(o options, v string) (options, error) { o.pidFile = v; return o, nil }, nil, nil, + func(o options) []string { return stringSliceOrNil(o.pidFile) }, } var checkConfigArg = arg{ "Check configuration and exit", "check-config", "", nil, func(o options) (options, error) { o.checkConfig = true; return o, nil }, nil, + func(o options) []string { return boolSliceOrNil(o.checkConfig) }, } var noCheckUpdateArg = arg{ "Don't check for updates", "no-check-update", "", nil, func(o options) (options, error) { o.disableUpdate = true; return o, nil }, nil, + func(o options) []string { return boolSliceOrNil(o.disableUpdate) }, } var verboseArg = arg{ "Enable verbose output", "verbose", "v", nil, func(o options) (options, error) { o.verbose = true; return o, nil }, nil, + func(o options) []string { return boolSliceOrNil(o.verbose) }, } var glinetArg = arg{ "Run in GL-Inet compatibility mode", "glinet", "", nil, func(o options) (options, error) { o.glinetMode = true; return o, nil }, nil, + func(o options) []string { return boolSliceOrNil(o.glinetMode) }, } var versionArg = arg{ @@ -133,6 +171,7 @@ var versionArg = arg{ nil, nil, func(o options, exec string) (effect, error) { return func() error { fmt.Println(version()); os.Exit(0); return nil }, nil }, + func(o options) []string { return nil }, } var helpArg = arg{ @@ -141,6 +180,7 @@ var helpArg = arg{ nil, nil, func(o options, exec string) (effect, error) { return func() error { _ = printHelp(exec); os.Exit(64); return nil }, nil }, + func(o options) []string { return nil }, } func init() { @@ -253,3 +293,21 @@ func parse(exec string, ss []string) (o options, f effect, err error) { return } + +func shortestFlag(a arg) string { + if a.shortName != "" { + return "-" + a.shortName + } + return "--" + a.longName +} + +func serialize(o options) []string { + ss := []string{} + for _, arg := range args { + s := arg.serialize(o) + if s != nil { + ss = append(ss, append([]string{shortestFlag(arg)}, s...)...) + } + } + return ss +} diff --git a/home/options_test.go b/home/options_test.go index 750f3ce2..5a2b1155 100644 --- a/home/options_test.go +++ b/home/options_test.go @@ -169,3 +169,69 @@ func TestParseUnknown(t *testing.T) { testParseErr(t, "unknown plus", "+x") testParseErr(t, "unknown dash", "-") } + +func testSerialize(t *testing.T, o options, ss ...string) { + result := serialize(o) + if len(result) != len(ss) { + t.Fatalf("expected %s but got %s", ss, result) + } + for i, r := range result { + if r != ss[i] { + t.Fatalf("expected %s but got %s", ss, result) + } + } +} + +func TestSerializeEmpty(t *testing.T) { + testSerialize(t, options{}) +} + +func TestSerializeConfigFilename(t *testing.T) { + testSerialize(t, options{configFilename: "path"}, "-c", "path") +} + +func TestSerializeWorkDir(t *testing.T) { + testSerialize(t, options{workDir: "path"}, "-w", "path") +} + +func TestSerializeBindHost(t *testing.T) { + testSerialize(t, options{bindHost: "addr"}, "-h", "addr") +} + +func TestSerializeBindPort(t *testing.T) { + testSerialize(t, options{bindPort: 666}, "-p", "666") +} + +func TestSerializeLogfile(t *testing.T) { + testSerialize(t, options{logFile: "path"}, "-l", "path") +} + +func TestSerializePidfile(t *testing.T) { + testSerialize(t, options{pidFile: "path"}, "--pidfile", "path") +} + +func TestSerializeCheckConfig(t *testing.T) { + testSerialize(t, options{checkConfig: true}, "--check-config") +} + +func TestSerializeDisableUpdate(t *testing.T) { + testSerialize(t, options{disableUpdate: true}, "--no-check-update") +} + +func TestSerializeService(t *testing.T) { + testSerialize(t, options{serviceControlAction: "run"}, "-s", "run") +} + +func TestSerializeGLInet(t *testing.T) { + testSerialize(t, options{glinetMode: true}, "--glinet") +} + +func TestSerializeMultiple(t *testing.T) { + testSerialize(t, options{ + serviceControlAction: "run", + configFilename: "config", + workDir: "work", + pidFile: "pid", + disableUpdate: true, + }, "-c", "config", "-w", "work", "-s", "run", "--pidfile", "pid", "--no-check-update") +} From 9e87f0afed6f26605adb1661cdc32f5c07947c02 Mon Sep 17 00:00:00 2001 From: David Sheets Date: Mon, 7 Sep 2020 10:04:31 +0100 Subject: [PATCH 10/19] home/auth: disable non-crypto RNG gosec lint check for session salt Fixes #2078. --- home/auth.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/home/auth.go b/home/auth.go index 36e56d05..afb7f0ed 100644 --- a/home/auth.go +++ b/home/auth.go @@ -276,7 +276,11 @@ type loginJSON struct { } func getSession(u *User) []byte { - d := []byte(fmt.Sprintf("%d%s%s", rand.Uint32(), u.Name, u.PasswordHash)) + // the developers don't currently believe that using a + // non-cryptographic RNG for the session hash salt is + // insecure + salt := rand.Uint32() //nolint:gosec + d := []byte(fmt.Sprintf("%d%s%s", salt, u.Name, u.PasswordHash)) hash := sha256.Sum256(d) return hash[:] } From 90ef204d0473c9df6bba468f33f2669a0bcf519f Mon Sep 17 00:00:00 2001 From: David Sheets Date: Mon, 7 Sep 2020 10:26:40 +0100 Subject: [PATCH 11/19] service: installation and running of AGH as a service with CLI args --- home/home.go | 2 +- home/service.go | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/home/home.go b/home/home.go index 806c59e2..898fb4bd 100644 --- a/home/home.go +++ b/home/home.go @@ -126,7 +126,7 @@ func Main(version string, channel string, armVer string) { }() if args.serviceControlAction != "" { - handleServiceControlAction(args.serviceControlAction) + handleServiceControlAction(args) return } diff --git a/home/service.go b/home/service.go index 21c9cfc6..b48c743b 100644 --- a/home/service.go +++ b/home/service.go @@ -24,12 +24,14 @@ const ( // Represents the program that will be launched by a service or daemon type program struct { + 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. - args := options{runningAsService: true} + args := p.opts + args.runningAsService = true go run(args) return nil } @@ -125,7 +127,8 @@ func sendSigReload() { // run - this is a special command that is not supposed to be used directly // 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(action string) { +func handleServiceControlAction(opts options) { + action := opts.serviceControlAction log.Printf("Service control action: %s", action) if action == "reload" { @@ -137,15 +140,17 @@ func handleServiceControlAction(action string) { if err != nil { log.Fatal("Unable to find the path to the current directory") } + runOpts := opts + runOpts.serviceControlAction = "run" svcConfig := &service.Config{ Name: serviceName, DisplayName: serviceDisplayName, Description: serviceDescription, WorkingDirectory: pwd, - Arguments: []string{"-s", "run"}, + Arguments: serialize(runOpts), } configureService(svcConfig) - prg := &program{} + prg := &program{runOpts} s, err := service.New(prg, svcConfig) if err != nil { log.Fatal(err) From 14bc5297ac6cb7c6dbc74d55239eeb16c041c048 Mon Sep 17 00:00:00 2001 From: ArtemBaskal Date: Mon, 7 Sep 2020 13:50:03 +0300 Subject: [PATCH 12/19] + client: Add experimental DNS-over-QUIC support --- client/src/__locales/en.json | 8 +++++ client/src/actions/encryption.js | 2 ++ .../Settings/Dns/Upstream/Examples.js | 19 +++++++++++ .../components/Settings/Encryption/Form.js | 33 +++++++++++++++++-- .../components/Settings/Encryption/index.js | 2 ++ client/src/components/Settings/Settings.css | 2 +- client/src/helpers/constants.js | 1 + client/src/helpers/validators.js | 6 ++++ 8 files changed, 70 insertions(+), 3 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 6cce0d91..58e270be 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -186,6 +186,7 @@ "example_upstream_regular": "regular DNS (over UDP)", "example_upstream_dot": "encrypted <0>DNS-over-TLS", "example_upstream_doh": "encrypted <0>DNS-over-HTTPS", + "example_upstream_doq": "encrypted <0>DNS-over-QUIC", "example_upstream_sdns": "you can use <0>DNS Stamps for <1>DNSCrypt or <2>DNS-over-HTTPS resolvers", "example_upstream_tcp": "regular DNS (over TCP)", "all_lists_up_to_date_toast": "All lists are already up-to-date", @@ -330,6 +331,8 @@ "encryption_https_desc": "If HTTPS port is configured, AdGuard Home admin interface will be accessible via HTTPS, and it will also provide DNS-over-HTTPS on '/dns-query' location.", "encryption_dot": "DNS-over-TLS port", "encryption_dot_desc": "If this port is configured, AdGuard Home will run a DNS-over-TLS server on this port.", + "encryption_doq": "DNS-over-QUIC port", + "encryption_doq_desc": "If this port is configured, AdGuard Home will run a DNS-over-QUIC server on this port. It's experimental and may not be reliable at the moment. The only DNS provider that supports it now is AdGuard DNS", "encryption_certificates": "Certificates", "encryption_certificates_desc": "In order to use encryption, you need to provide a valid SSL certificates chain for your domain. You can get a free certificate on <0>{{link}} or you can buy it from one of the trusted Certificate Authorities.", "encryption_certificates_input": "Copy/paste your PEM-encoded certificates here.", @@ -574,5 +577,10 @@ "original_response": "Original response", "click_to_view_queries": "Click to view queries", "port_53_faq_link": "Port 53 is often occupied by \"DNSStubListener\" or \"systemd-resolved\" services. Please read <0>this instruction on how to resolve this.", +<<<<<<< Updated upstream "adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client." +======= + "adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client.", + "experimental": "Experimental" +>>>>>>> Stashed changes } diff --git a/client/src/actions/encryption.js b/client/src/actions/encryption.js index 0e743323..36faf2ec 100644 --- a/client/src/actions/encryption.js +++ b/client/src/actions/encryption.js @@ -34,6 +34,7 @@ export const setTlsConfig = (config) => async (dispatch, getState) => { values.private_key = btoa(values.private_key); values.port_https = values.port_https || 0; values.port_dns_over_tls = values.port_dns_over_tls || 0; + values.port_dns_over_quic = values.port_dns_over_quic || 0; const response = await apiClient.setTlsConfig(values); response.certificate_chain = atob(response.certificate_chain); @@ -59,6 +60,7 @@ export const validateTlsConfig = (config) => async (dispatch) => { values.private_key = btoa(values.private_key); values.port_https = values.port_https || 0; values.port_dns_over_tls = values.port_dns_over_tls || 0; + values.port_dns_over_quic = values.port_dns_over_quic || 0; const response = await apiClient.validateTlsConfig(values); response.certificate_chain = atob(response.certificate_chain); diff --git a/client/src/components/Settings/Dns/Upstream/Examples.js b/client/src/components/Settings/Dns/Upstream/Examples.js index de779b18..a18c1c90 100644 --- a/client/src/components/Settings/Dns/Upstream/Examples.js +++ b/client/src/components/Settings/Dns/Upstream/Examples.js @@ -63,6 +63,25 @@ const Examples = (props) => ( +
  • + quic://dns-unfiltered.adguard.com:784 –  + + + DNS-over-QUIC + , + ]} + > + example_upstream_doq + + +
  • tcp://9.9.9.9example_upstream_tcp
  • diff --git a/client/src/components/Settings/Encryption/Form.js b/client/src/components/Settings/Encryption/Form.js index 7be23b10..ee56b315 100644 --- a/client/src/components/Settings/Encryption/Form.js +++ b/client/src/components/Settings/Encryption/Form.js @@ -11,11 +11,15 @@ import { renderRadioField, toNumber, } from '../../../helpers/form'; -import { validateIsSafePort, validatePort, validatePortTLS } from '../../../helpers/validators'; +import { + validateIsSafePort, validatePort, validatePortQuic, validatePortTLS, +} from '../../../helpers/validators'; import i18n from '../../../i18n'; import KeyStatus from './KeyStatus'; import CertificateStatus from './CertificateStatus'; -import { DNS_OVER_TLS_PORT, FORM_NAME, STANDARD_HTTPS_PORT } from '../../../helpers/constants'; +import { + DNS_OVER_QUIC_PORT, DNS_OVER_TLS_PORT, FORM_NAME, STANDARD_HTTPS_PORT, +} from '../../../helpers/constants'; const validate = (values) => { const errors = {}; @@ -38,6 +42,7 @@ const clearFields = (change, setTlsConfig, t) => { certificate_path: '', port_https: STANDARD_HTTPS_PORT, port_dns_over_tls: DNS_OVER_TLS_PORT, + port_dns_over_quic: DNS_OVER_QUIC_PORT, server_name: '', force_https: false, enabled: false, @@ -189,6 +194,30 @@ let Form = (props) => {
    +
    +
    + + +
    + encryption_doq_desc +
    +
    +
    diff --git a/client/src/components/Settings/Encryption/index.js b/client/src/components/Settings/Encryption/index.js index 7c2cccc8..f7ca52e0 100644 --- a/client/src/components/Settings/Encryption/index.js +++ b/client/src/components/Settings/Encryption/index.js @@ -66,6 +66,7 @@ class Encryption extends Component { force_https, port_https, port_dns_over_tls, + port_dns_over_quic, certificate_chain, private_key, certificate_path, @@ -78,6 +79,7 @@ class Encryption extends Component { force_https, port_https, port_dns_over_tls, + port_dns_over_quic, certificate_chain, private_key, certificate_path, diff --git a/client/src/components/Settings/Settings.css b/client/src/components/Settings/Settings.css index 3bf1a121..4efb0868 100644 --- a/client/src/components/Settings/Settings.css +++ b/client/src/components/Settings/Settings.css @@ -54,7 +54,7 @@ } .form__message--error { - color: var(--red); + color: #cd201f; } .form__message--left-pad { diff --git a/client/src/helpers/constants.js b/client/src/helpers/constants.js index e0075a25..1020a50c 100644 --- a/client/src/helpers/constants.js +++ b/client/src/helpers/constants.js @@ -69,6 +69,7 @@ export const STANDARD_DNS_PORT = 53; export const STANDARD_WEB_PORT = 80; export const STANDARD_HTTPS_PORT = 443; export const DNS_OVER_TLS_PORT = 853; +export const DNS_OVER_QUIC_PORT = 784; export const MAX_PORT = 65535; export const EMPTY_DATE = '0001-01-01T00:00:00Z'; diff --git a/client/src/helpers/validators.js b/client/src/helpers/validators.js index 45055154..64c5fa49 100644 --- a/client/src/helpers/validators.js +++ b/client/src/helpers/validators.js @@ -180,6 +180,12 @@ export const validatePortTLS = (value) => { return undefined; }; +/** + * @param value {number} + * @returns {undefined|string} + */ +export const validatePortQuic = validatePortTLS; + /** * @param value {number} * @returns {undefined|string} From 4d1666eff1f5643dab485e35051677c103dd20b2 Mon Sep 17 00:00:00 2001 From: ArtemBaskal Date: Mon, 7 Sep 2020 13:52:23 +0300 Subject: [PATCH 13/19] Resolve conflict --- client/src/__locales/en.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 58e270be..eafb667b 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -577,10 +577,6 @@ "original_response": "Original response", "click_to_view_queries": "Click to view queries", "port_53_faq_link": "Port 53 is often occupied by \"DNSStubListener\" or \"systemd-resolved\" services. Please read <0>this instruction on how to resolve this.", -<<<<<<< Updated upstream - "adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client." -======= "adg_will_drop_dns_queries": "AdGuard Home will be dropping all DNS queries from this client.", "experimental": "Experimental" ->>>>>>> Stashed changes } From 9f3c27c03a6fcba71ee84e3826c3e10bd270c348 Mon Sep 17 00:00:00 2001 From: ArtemBaskal Date: Tue, 8 Sep 2020 10:17:39 +0300 Subject: [PATCH 14/19] Change link and translation --- client/src/__locales/en.json | 2 +- client/src/components/Settings/Dns/Upstream/Examples.js | 4 +++- client/src/components/Settings/Encryption/Form.js | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index eafb667b..6abd1d4c 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -332,7 +332,7 @@ "encryption_dot": "DNS-over-TLS port", "encryption_dot_desc": "If this port is configured, AdGuard Home will run a DNS-over-TLS server on this port.", "encryption_doq": "DNS-over-QUIC port", - "encryption_doq_desc": "If this port is configured, AdGuard Home will run a DNS-over-QUIC server on this port. It's experimental and may not be reliable at the moment. The only DNS provider that supports it now is AdGuard DNS", + "encryption_doq_desc": "If this port is configured, AdGuard Home will run a DNS-over-QUIC server on this port. It's experimental and may not be reliable. Also, there are not too many clients that support it at the moment.", "encryption_certificates": "Certificates", "encryption_certificates_desc": "In order to use encryption, you need to provide a valid SSL certificates chain for your domain. You can get a free certificate on <0>{{link}} or you can buy it from one of the trusted Certificate Authorities.", "encryption_certificates_input": "Copy/paste your PEM-encoded certificates here.", diff --git a/client/src/components/Settings/Dns/Upstream/Examples.js b/client/src/components/Settings/Dns/Upstream/Examples.js index a18c1c90..70797909 100644 --- a/client/src/components/Settings/Dns/Upstream/Examples.js +++ b/client/src/components/Settings/Dns/Upstream/Examples.js @@ -69,7 +69,7 @@ const Examples = (props) => ( ( > example_upstream_doq +   + (experimental)
  • diff --git a/client/src/components/Settings/Encryption/Form.js b/client/src/components/Settings/Encryption/Form.js index ee56b315..15f8a3c6 100644 --- a/client/src/components/Settings/Encryption/Form.js +++ b/client/src/components/Settings/Encryption/Form.js @@ -199,7 +199,7 @@ let Form = (props) => { Date: Tue, 8 Sep 2020 13:18:19 +0300 Subject: [PATCH 15/19] - client: Add link to 'update_failed' error toast Close #2062 Squashed commit of the following: commit a1a1d4fe74dd414f83477d972bc07062e2c890ab Merge: 9535e109 84938c56 Author: ArtemBaskal Date: Tue Sep 8 10:21:47 2020 +0300 Merge branch 'master' into fix/2062 commit 9535e10934c57c2592df234a030bad183c0086cd Author: ArtemBaskal Date: Mon Sep 7 13:59:57 2020 +0300 Fix translation commit e6f912d1d2793fd008c22b4418681abcc54896d0 Author: ArtemBaskal Date: Mon Sep 7 12:03:45 2020 +0300 - client: Add link to 'update_failed' error toast --- client/package-lock.json | 6 +++--- client/package.json | 2 +- client/src/__locales/en.json | 2 +- client/src/actions/index.js | 12 ++++++++++-- client/src/components/Toasts/Toast.js | 12 +++++++++--- client/src/helpers/constants.js | 13 ++++++++----- client/src/reducers/toasts.js | 2 ++ 7 files changed, 34 insertions(+), 15 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 84c8e186..42cac10f 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -12377,9 +12377,9 @@ } }, "react-i18next": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.4.0.tgz", - "integrity": "sha512-lyOZSSQkif4H9HnHN3iEKVkryLI+WkdZSEw3VAZzinZLopfYRMHVY5YxCopdkXPLEHs6S5GjKYPh3+j0j336Fg==", + "version": "11.7.2", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.7.2.tgz", + "integrity": "sha512-Djj3K3hh5Tecla2CI9rLO3TZBYGMFrGilm0JY4cLofAQONCi5TK6nVmUPKoB59n1ZffgjfgJt6zlbE9aGF6Q0Q==", "requires": { "@babel/runtime": "^7.3.1", "html-parse-stringify2": "2.0.1" diff --git a/client/package.json b/client/package.json index fdc19c9d..4ad8d5eb 100644 --- a/client/package.json +++ b/client/package.json @@ -28,7 +28,7 @@ "react": "^16.13.1", "react-click-outside": "^3.0.1", "react-dom": "^16.13.1", - "react-i18next": "^11.4.0", + "react-i18next": "^11.7.2", "react-modal": "^3.11.2", "react-popper-tooltip": "^2.11.1", "react-redux": "^7.2.0", diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json index 6cce0d91..56b6988f 100644 --- a/client/src/__locales/en.json +++ b/client/src/__locales/en.json @@ -363,7 +363,7 @@ "fix": "Fix", "dns_providers": "Here is a <0>list of known DNS providers to choose from.", "update_now": "Update now", - "update_failed": "Auto-update failed. Please follow the steps to update manually.", + "update_failed": "Auto-update failed. Please follow these steps to update manually.", "processing_update": "Please wait, AdGuard Home is being updated", "clients_title": "Clients", "clients_desc": "Configure devices connected to AdGuard Home", diff --git a/client/src/actions/index.js b/client/src/actions/index.js index d4018bb0..ff039af1 100644 --- a/client/src/actions/index.js +++ b/client/src/actions/index.js @@ -4,9 +4,10 @@ import axios from 'axios'; import endsWith from 'lodash/endsWith'; import escapeRegExp from 'lodash/escapeRegExp'; +import React from 'react'; import { splitByNewLine, sortClients } from '../helpers/helpers'; import { - BLOCK_ACTIONS, CHECK_TIMEOUT, STATUS_RESPONSE, SETTINGS_NAMES, FORM_NAME, + BLOCK_ACTIONS, CHECK_TIMEOUT, STATUS_RESPONSE, SETTINGS_NAMES, FORM_NAME, GETTING_STARTED_LINK, } from '../helpers/constants'; import { areEqualVersions } from '../helpers/version'; import { getTlsStatus } from './encryption'; @@ -184,7 +185,14 @@ export const getUpdate = () => async (dispatch, getState) => { dispatch(getUpdateRequest()); const handleRequestError = () => { - dispatch(addNoticeToast({ error: 'update_failed' })); + const options = { + components: { + a: , + }, + }; + + dispatch(addNoticeToast({ error: 'update_failed', options })); dispatch(getUpdateFailure()); }; diff --git a/client/src/components/Toasts/Toast.js b/client/src/components/Toasts/Toast.js index a4c58aad..4c46078a 100644 --- a/client/src/components/Toasts/Toast.js +++ b/client/src/components/Toasts/Toast.js @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; -import { useTranslation } from 'react-i18next'; +import { Trans } from 'react-i18next'; import { useDispatch } from 'react-redux'; import { TOAST_TIMEOUTS } from '../../helpers/constants'; import { removeToast } from '../../actions'; @@ -9,8 +9,8 @@ const Toast = ({ id, message, type, + options, }) => { - const { t } = useTranslation(); const dispatch = useDispatch(); const [timerId, setTimerId] = useState(null); @@ -30,7 +30,12 @@ const Toast = ({ return
    -

    {t(message)}

    +

    + +