Compare commits

...

5 Commits

Author SHA1 Message Date
Ildar Kamalov
d3f39b0aa1 Pull request: 4637 fix blocked services icons and actions highlight
Updates #4637

Squashed commit of the following:

commit d69887586d15582406fab642e576a46f8984107b
Merge: 65453371 e738508d
Author: Ildar Kamalov <ik@adguard.com>
Date:   Fri Jun 10 12:07:29 2022 +0300

    Merge branch 'master' into 4637-table

commit 65453371fc7309e772a12fb9f522247e1392a64a
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jun 9 18:43:44 2022 +0300

    client: fix blocked services icons and actions highlight
2022-06-10 12:41:20 +03:00
Ainar Garipov
e738508d7a Pull request: all: imp updater
Merge in DNS/adguard-home from imp-updater to master

Squashed commit of the following:

commit 6ed487359e56a35b36f13dcbf2efbf2a7a2d8734
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jun 9 16:29:35 2022 +0300

    all: imp logs, err handling

commit e930044cb619a43e5a44c230dadbe2228e9a93f5
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Jun 9 15:53:35 2022 +0300

    all: imp updater
2022-06-09 17:47:05 +03:00
Ildar Kamalov
302faca32f Pull request: 4642 update dns addresses on encryption update
Updates #4642

Squashed commit of the following:

commit 75729120d3532dc2bd12b6c9e724a691043a1870
Merge: 5b681867 1c1ca1c6
Author: Ildar Kamalov <ik@adguard.com>
Date:   Thu Jun 9 11:58:13 2022 +0300

    Merge branch 'master' into 4642-dns-privacy

commit 5b68186705c3a9287a44e33c8cf7ab79060f35a4
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Jun 7 18:39:02 2022 +0300

    fix

commit 46a9346154d33206e829a97021f3ef47ac2a5611
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Jun 7 18:18:18 2022 +0300

    client: update dns addresses on encryption update
2022-06-09 12:07:29 +03:00
Ildar Kamalov
1c1ca1c6e3 Pull request: 4641 fix button clickable area
Updates #4641

Squashed commit of the following:

commit f9f018388a198d7712e5caabba94035e42e393c4
Author: Ildar Kamalov <ik@adguard.com>
Date:   Tue Jun 7 16:21:37 2022 +0300

    client: fix button clickable area
2022-06-09 11:57:58 +03:00
Ainar Garipov
a497dc09ca Pull request: all: upd chlog
Merge in DNS/adguard-home from upd-chlog to master

Squashed commit of the following:

commit 1ca912f4be4a452abc0c8c95a8d6022d547b3394
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Mon Jun 6 18:35:12 2022 +0300

    all: upd chlog
2022-06-06 18:43:35 +03:00
18 changed files with 191 additions and 151 deletions

View File

@ -12,24 +12,52 @@ and this project adheres to
## [Unreleased] ## [Unreleased]
<!-- <!--
## [v0.108.0] - 2022-07-01 (APPROX.) ## [v0.108.0] - 2022-10-01 (APPROX.)
--> -->
### Security ### Security
- Weaker cipher suites that use the CBC (cipher block chaining) mode of
operation have been disabled ([#2993]).
### Added
- Support for Discovery of Designated Resolvers (DDR) according to the [RFC
draft][ddr-draft-06] ([#4463]).
- `windows/arm64` support ([#3057]).
### Deprecated
- Go 1.17 support. v0.109.0 will require at least Go 1.18 to build.
[#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993
[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057
[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html
<!--
## [v0.107.8] - 2022-07-12 (APPROX.)
-->
## [v0.107.7] - 2022-06-06
See also the [v0.107.7 GitHub milestone][ms-v0.107.7].
### Security
- Go version was updated to prevent the possibility of exploiting the - Go version was updated to prevent the possibility of exploiting the
[CVE-2022-29526], [CVE-2022-30634], [CVE-2022-30629], [CVE-2022-30580], and [CVE-2022-29526], [CVE-2022-30634], [CVE-2022-30629], [CVE-2022-30580], and
[CVE-2022-29804] vulnerabilities. [CVE-2022-29804] vulnerabilities.
- Enforced password strength policy ([#3503]). - Enforced password strength policy ([#3503]).
- Weaker cipher suites that use the CBC (cipher block chaining) mode of
operation have been disabled ([#2993]).
### Added ### Added
- Support for the final DNS-over-QUIC standard, [RFC 9250][rfc-9250] ([#4592]). - Support for the final DNS-over-QUIC standard, [RFC 9250][rfc-9250] ([#4592]).
- Support upstreams for subdomains of a domain only ([#4503]). - Support upstreams for subdomains of a domain only ([#4503]).
- Support for Discovery of Designated Resolvers (DDR) according to the [RFC
draft][ddr-draft-06] ([#4463]).
- The ability to control each source of runtime clients separately via - The ability to control each source of runtime clients separately via
`clients.runtime_sources` configuration object ([#3020]). `clients.runtime_sources` configuration object ([#3020]).
- The ability to customize the set of networks that are considered private - The ability to customize the set of networks that are considered private
@ -41,7 +69,6 @@ and this project adheres to
([#4166]). ([#4166]).
- Logs are now collected by default on FreeBSD and OpenBSD when AdGuard Home is - Logs are now collected by default on FreeBSD and OpenBSD when AdGuard Home is
installed as a service ([#4213]). installed as a service ([#4213]).
- `windows/arm64` support ([#3057]).
### Changed ### Changed
@ -125,10 +152,9 @@ In this release, the schema version has changed from 12 to 14.
### Deprecated ### Deprecated
- The `--no-etc-hosts` option. Its' functionality is now controlled by - The `--no-etc-hosts` option. Its functionality is now controlled by
`clients.runtime_sources.hosts` configuration property. v0.109.0 will remove `clients.runtime_sources.hosts` configuration property. v0.109.0 will remove
the flag completely. the flag completely.
- Go 1.17 support. v0.109.0 will require at least Go 1.18 to build.
### Fixed ### Fixed
@ -140,9 +166,7 @@ In this release, the schema version has changed from 12 to 14.
- ARP tables refreshing process causing excessive PTR requests ([#3157]). - ARP tables refreshing process causing excessive PTR requests ([#3157]).
[#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730 [#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730
[#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993
[#3020]: https://github.com/AdguardTeam/AdGuardHome/issues/3020 [#3020]: https://github.com/AdguardTeam/AdGuardHome/issues/3020
[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057
[#3142]: https://github.com/AdguardTeam/AdGuardHome/issues/3142 [#3142]: https://github.com/AdguardTeam/AdGuardHome/issues/3142
[#3157]: https://github.com/AdguardTeam/AdGuardHome/issues/3157 [#3157]: https://github.com/AdguardTeam/AdGuardHome/issues/3157
[#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367 [#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367
@ -169,20 +193,10 @@ In this release, the schema version has changed from 12 to 14.
[CVE-2022-30580]: https://www.cvedetails.com/cve/CVE-2022-30580 [CVE-2022-30580]: https://www.cvedetails.com/cve/CVE-2022-30580
[CVE-2022-30629]: https://www.cvedetails.com/cve/CVE-2022-30629 [CVE-2022-30629]: https://www.cvedetails.com/cve/CVE-2022-30629
[CVE-2022-30634]: https://www.cvedetails.com/cve/CVE-2022-30634 [CVE-2022-30634]: https://www.cvedetails.com/cve/CVE-2022-30634
[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html [ms-v0.107.7]: https://github.com/AdguardTeam/AdGuardHome/milestone/43?closed=1
[repr]: https://reproducible-builds.org/docs/source-date-epoch/
[rfc-9250]: https://datatracker.ietf.org/doc/html/rfc9250 [rfc-9250]: https://datatracker.ietf.org/doc/html/rfc9250
<!--
## [v0.107.7] - 2022-05-18 (APPROX.)
See also the [v0.107.7 GitHub milestone][ms-v0.107.7].
[ms-v0.107.7]: https://github.com/AdguardTeam/AdGuardHome/milestone/43?closed=1
-->
## [v0.107.6] - 2022-04-13 ## [v0.107.6] - 2022-04-13
@ -234,6 +248,7 @@ See also the [v0.107.6 GitHub milestone][ms-v0.107.6].
[CVE-2022-28327]: https://www.cvedetails.com/cve/CVE-2022-28327 [CVE-2022-28327]: https://www.cvedetails.com/cve/CVE-2022-28327
[dns-draft-02]: https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02#section-5.1 [dns-draft-02]: https://datatracker.ietf.org/doc/html/draft-ietf-add-svcb-dns-02#section-5.1
[ms-v0.107.6]: https://github.com/AdguardTeam/AdGuardHome/milestone/42?closed=1 [ms-v0.107.6]: https://github.com/AdguardTeam/AdGuardHome/milestone/42?closed=1
[repr]: https://reproducible-builds.org/docs/source-date-epoch/
[svcb-draft-08]: https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-08.html [svcb-draft-08]: https://www.ietf.org/archive/id/draft-ietf-dnsop-svcb-https-08.html
@ -995,11 +1010,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
<!-- <!--
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.7...HEAD [Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.8...HEAD
[v0.107.7]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.6...v0.107.7 [v0.107.8]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.7...v0.107.8
--> -->
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.6...HEAD [Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.7...HEAD
[v0.107.7]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.6...v0.107.7
[v0.107.6]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.5...v0.107.6 [v0.107.6]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.5...v0.107.6
[v0.107.5]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.4...v0.107.5 [v0.107.5]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.4...v0.107.5
[v0.107.4]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.3...v0.107.4 [v0.107.4]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.3...v0.107.4

View File

@ -445,7 +445,7 @@
"access_blocked_title": "Disallowed domains", "access_blocked_title": "Disallowed domains",
"access_blocked_desc": "Not to be confused with filters. AdGuard Home drops DNS queries matching these domains, and these queries don't even appear in the query log. You can specify exact domain names, wildcards, or URL filter rules, e.g. \"example.org\", \"*.example.org\", or \"||example.org^\" correspondingly.", "access_blocked_desc": "Not to be confused with filters. AdGuard Home drops DNS queries matching these domains, and these queries don't even appear in the query log. You can specify exact domain names, wildcards, or URL filter rules, e.g. \"example.org\", \"*.example.org\", or \"||example.org^\" correspondingly.",
"access_settings_saved": "Access settings successfully saved", "access_settings_saved": "Access settings successfully saved",
"updates_checked": "Updates successfully checked", "updates_checked": "A new version of AdGuard Home is available",
"updates_version_equal": "AdGuard Home is up-to-date", "updates_version_equal": "AdGuard Home is up-to-date",
"check_updates_now": "Check for updates now", "check_updates_now": "Check for updates now",
"dns_privacy": "DNS Privacy", "dns_privacy": "DNS Privacy",

View File

@ -24,6 +24,7 @@ export const getTlsStatus = () => async (dispatch) => {
export const setTlsConfigRequest = createAction('SET_TLS_CONFIG_REQUEST'); export const setTlsConfigRequest = createAction('SET_TLS_CONFIG_REQUEST');
export const setTlsConfigFailure = createAction('SET_TLS_CONFIG_FAILURE'); export const setTlsConfigFailure = createAction('SET_TLS_CONFIG_FAILURE');
export const setTlsConfigSuccess = createAction('SET_TLS_CONFIG_SUCCESS'); export const setTlsConfigSuccess = createAction('SET_TLS_CONFIG_SUCCESS');
export const dnsStatusSuccess = createAction('DNS_STATUS_SUCCESS');
export const setTlsConfig = (config) => async (dispatch, getState) => { export const setTlsConfig = (config) => async (dispatch, getState) => {
dispatch(setTlsConfigRequest()); dispatch(setTlsConfigRequest());
@ -39,6 +40,12 @@ export const setTlsConfig = (config) => async (dispatch, getState) => {
const response = await apiClient.setTlsConfig(values); const response = await apiClient.setTlsConfig(values);
response.certificate_chain = atob(response.certificate_chain); response.certificate_chain = atob(response.certificate_chain);
response.private_key = atob(response.private_key); response.private_key = atob(response.private_key);
const dnsStatus = await apiClient.getGlobalStatus();
if (dnsStatus) {
dispatch(dnsStatusSuccess(dnsStatus));
}
dispatch(setTlsConfigSuccess(response)); dispatch(setTlsConfigSuccess(response));
dispatch(addSuccessToast('encryption_config_saved')); dispatch(addSuccessToast('encryption_config_saved'));
redirectToCurrentProtocol(response, httpPort); redirectToCurrentProtocol(response, httpPort);

View File

@ -29,6 +29,8 @@ class Table extends Component {
Header: this.props.t('actions_table_header'), Header: this.props.t('actions_table_header'),
accessor: 'actions', accessor: 'actions',
maxWidth: 100, maxWidth: 100,
sortable: false,
resizable: false,
Cell: (value) => ( Cell: (value) => (
<div className="logs__row logs__row--center"> <div className="logs__row logs__row--center">
<button <button

View File

@ -36,6 +36,7 @@ class Table extends Component {
Cell: this.renderCheckbox, Cell: this.renderCheckbox,
width: 90, width: 90,
className: 'text-center', className: 'text-center',
resizable: false,
}, },
{ {
Header: <Trans>name_table_header</Trans>, Header: <Trans>name_table_header</Trans>,
@ -77,10 +78,11 @@ class Table extends Component {
}, },
{ {
Header: <Trans>actions_table_header</Trans>, Header: <Trans>actions_table_header</Trans>,
accessor: 'url', accessor: 'actions',
className: 'text-center', className: 'text-center',
width: 100, width: 100,
sortable: false, sortable: false,
resizable: false,
Cell: (row) => { Cell: (row) => {
const { value } = row; const { value } = row;
const { t, toggleFilteringModal, handleDelete } = this.props; const { t, toggleFilteringModal, handleDelete } = this.props;

View File

@ -338,10 +338,19 @@
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.logs__row--icons {
flex-wrap: wrap;
}
.logs__table .logs__row { .logs__table .logs__row {
border-bottom: 2px solid var(--gray-216); border-bottom: 2px solid var(--gray-216);
} }
.logs__tag {
text-overflow: ellipsis;
overflow: hidden;
}
/* QUERY_STATUS_COLORS */ /* QUERY_STATUS_COLORS */
.logs__row--blue { .logs__row--blue {
background-color: var(--blue); background-color: var(--blue);

View File

@ -193,7 +193,7 @@ class ClientsTable extends Component {
<div className="logs__row o-hidden"> <div className="logs__row o-hidden">
<span className="logs__text"> <span className="logs__text">
{value.map((tag) => ( {value.map((tag) => (
<div key={tag} title={tag} className="small"> <div key={tag} title={tag} className="logs__tag small">
{tag} {tag}
</div> </div>
))} ))}
@ -225,6 +225,8 @@ class ClientsTable extends Component {
Header: this.props.t('actions_table_header'), Header: this.props.t('actions_table_header'),
accessor: 'actions', accessor: 'actions',
maxWidth: 100, maxWidth: 100,
sortable: false,
resizable: false,
Cell: (row) => { Cell: (row) => {
const clientName = row.original.name; const clientName = row.original.name;
const { const {

View File

@ -70,6 +70,8 @@ const StaticLeases = ({
Header: <Trans>actions_table_header</Trans>, Header: <Trans>actions_table_header</Trans>,
accessor: 'actions', accessor: 'actions',
maxWidth: 150, maxWidth: 150,
sortable: false,
resizable: false,
// eslint-disable-next-line react/display-name // eslint-disable-next-line react/display-name
Cell: (row) => { Cell: (row) => {
const { ip, mac, hostname } = row.original; const { ip, mac, hostname } = row.original;

View File

@ -113,6 +113,7 @@
width: 30px; width: 30px;
height: 30px; height: 30px;
background-color: transparent; background-color: transparent;
overflow: hidden;
} }
.btn-icon--green { .btn-icon--green {

View File

@ -0,0 +1,59 @@
package aghalg
import (
"bytes"
"encoding/json"
"fmt"
)
// NullBool is a nullable boolean. Use these in JSON requests and responses
// instead of pointers to bool.
type NullBool uint8
// NullBool values
const (
NBNull NullBool = iota
NBTrue
NBFalse
)
// String implements the fmt.Stringer interface for NullBool.
func (nb NullBool) String() (s string) {
switch nb {
case NBNull:
return "null"
case NBTrue:
return "true"
case NBFalse:
return "false"
}
return fmt.Sprintf("!invalid NullBool %d", uint8(nb))
}
// BoolToNullBool converts a bool into a NullBool.
func BoolToNullBool(cond bool) (nb NullBool) {
if cond {
return NBTrue
}
return NBFalse
}
// type check
var _ json.Unmarshaler = (*NullBool)(nil)
// UnmarshalJSON implements the json.Unmarshaler interface for *NullBool.
func (nb *NullBool) UnmarshalJSON(b []byte) (err error) {
if len(b) == 0 || bytes.Equal(b, []byte("null")) {
*nb = NBNull
} else if bytes.Equal(b, []byte("true")) {
*nb = NBTrue
} else if bytes.Equal(b, []byte("false")) {
*nb = NBFalse
} else {
return fmt.Errorf("unmarshalling json data into aghalg.NullBool: bad value %q", b)
}
return nil
}

View File

@ -1,9 +1,10 @@
package dhcpd package aghalg_test
import ( import (
"encoding/json" "encoding/json"
"testing" "testing"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/golibs/testutil"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -14,37 +15,37 @@ func TestNullBool_UnmarshalJSON(t *testing.T) {
name string name string
wantErrMsg string wantErrMsg string
data []byte data []byte
want nullBool want aghalg.NullBool
}{{ }{{
name: "empty", name: "empty",
wantErrMsg: "", wantErrMsg: "",
data: []byte{}, data: []byte{},
want: nbNull, want: aghalg.NBNull,
}, { }, {
name: "null", name: "null",
wantErrMsg: "", wantErrMsg: "",
data: []byte("null"), data: []byte("null"),
want: nbNull, want: aghalg.NBNull,
}, { }, {
name: "true", name: "true",
wantErrMsg: "", wantErrMsg: "",
data: []byte("true"), data: []byte("true"),
want: nbTrue, want: aghalg.NBTrue,
}, { }, {
name: "false", name: "false",
wantErrMsg: "", wantErrMsg: "",
data: []byte("false"), data: []byte("false"),
want: nbFalse, want: aghalg.NBFalse,
}, { }, {
name: "invalid", name: "invalid",
wantErrMsg: `invalid nullBool value "invalid"`, wantErrMsg: `unmarshalling json data into aghalg.NullBool: bad value "invalid"`,
data: []byte("invalid"), data: []byte("invalid"),
want: nbNull, want: aghalg.NBNull,
}} }}
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
var got nullBool var got aghalg.NullBool
err := got.UnmarshalJSON(tc.data) err := got.UnmarshalJSON(tc.data)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err) testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
@ -53,9 +54,9 @@ func TestNullBool_UnmarshalJSON(t *testing.T) {
} }
t.Run("json", func(t *testing.T) { t.Run("json", func(t *testing.T) {
want := nbTrue want := aghalg.NBTrue
var got struct { var got struct {
A nullBool A aghalg.NullBool
} }
err := json.Unmarshal([]byte(`{"A":true}`), &got) err := json.Unmarshal([]byte(`{"A":true}`), &got)

View File

@ -10,6 +10,7 @@ import (
"strings" "strings"
"time" "time"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
@ -145,7 +146,7 @@ type dhcpServerConfigJSON struct {
V4 *v4ServerConfJSON `json:"v4"` V4 *v4ServerConfJSON `json:"v4"`
V6 *v6ServerConfJSON `json:"v6"` V6 *v6ServerConfJSON `json:"v6"`
InterfaceName string `json:"interface_name"` InterfaceName string `json:"interface_name"`
Enabled nullBool `json:"enabled"` Enabled aghalg.NullBool `json:"enabled"`
} }
func (s *Server) handleDHCPSetConfigV4( func (s *Server) handleDHCPSetConfigV4(
@ -156,7 +157,7 @@ func (s *Server) handleDHCPSetConfigV4(
} }
v4Conf := v4JSONToServerConf(conf.V4) v4Conf := v4JSONToServerConf(conf.V4)
v4Conf.Enabled = conf.Enabled == nbTrue v4Conf.Enabled = conf.Enabled == aghalg.NBTrue
if len(v4Conf.RangeStart) == 0 { if len(v4Conf.RangeStart) == 0 {
v4Conf.Enabled = false v4Conf.Enabled = false
} }
@ -183,7 +184,7 @@ func (s *Server) handleDHCPSetConfigV6(
} }
v6Conf := v6JSONToServerConf(conf.V6) v6Conf := v6JSONToServerConf(conf.V6)
v6Conf.Enabled = conf.Enabled == nbTrue v6Conf.Enabled = conf.Enabled == aghalg.NBTrue
if len(v6Conf.RangeStart) == 0 { if len(v6Conf.RangeStart) == 0 {
v6Conf.Enabled = false v6Conf.Enabled = false
} }
@ -206,7 +207,7 @@ func (s *Server) handleDHCPSetConfigV6(
func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) { func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
conf := &dhcpServerConfigJSON{} conf := &dhcpServerConfigJSON{}
conf.Enabled = boolToNullBool(s.conf.Enabled) conf.Enabled = aghalg.BoolToNullBool(s.conf.Enabled)
conf.InterfaceName = s.conf.InterfaceName conf.InterfaceName = s.conf.InterfaceName
err := json.NewDecoder(r.Body).Decode(conf) err := json.NewDecoder(r.Body).Decode(conf)
@ -230,7 +231,7 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
return return
} }
if conf.Enabled == nbTrue && !v4Enabled && !v6Enabled { if conf.Enabled == aghalg.NBTrue && !v4Enabled && !v6Enabled {
aghhttp.Error(r, w, http.StatusBadRequest, "dhcpv4 or dhcpv6 configuration must be complete") aghhttp.Error(r, w, http.StatusBadRequest, "dhcpv4 or dhcpv6 configuration must be complete")
return return
@ -243,8 +244,8 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
return return
} }
if conf.Enabled != nbNull { if conf.Enabled != aghalg.NBNull {
s.conf.Enabled = conf.Enabled == nbTrue s.conf.Enabled = conf.Enabled == aghalg.NBTrue
} }
if conf.InterfaceName != "" { if conf.InterfaceName != "" {
@ -279,11 +280,11 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
type netInterfaceJSON struct { type netInterfaceJSON struct {
Name string `json:"name"` Name string `json:"name"`
GatewayIP net.IP `json:"gateway_ip"`
HardwareAddr string `json:"hardware_address"` HardwareAddr string `json:"hardware_address"`
Flags string `json:"flags"`
GatewayIP net.IP `json:"gateway_ip"`
Addrs4 []net.IP `json:"ipv4_addresses"` Addrs4 []net.IP `json:"ipv4_addresses"`
Addrs6 []net.IP `json:"ipv6_addresses"` Addrs6 []net.IP `json:"ipv6_addresses"`
Flags string `json:"flags"`
} }
func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) { func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {

View File

@ -1,58 +0,0 @@
package dhcpd
import (
"bytes"
"fmt"
)
// nullBool is a nullable boolean. Use these in JSON requests and responses
// instead of pointers to bool.
//
// TODO(a.garipov): Inspect uses of *bool, move this type into some new package
// if we need it somewhere else.
type nullBool uint8
// nullBool values
const (
nbNull nullBool = iota
nbTrue
nbFalse
)
// String implements the fmt.Stringer interface for nullBool.
func (nb nullBool) String() (s string) {
switch nb {
case nbNull:
return "null"
case nbTrue:
return "true"
case nbFalse:
return "false"
}
return fmt.Sprintf("!invalid nullBool %d", uint8(nb))
}
// boolToNullBool converts a bool into a nullBool.
func boolToNullBool(cond bool) (nb nullBool) {
if cond {
return nbTrue
}
return nbFalse
}
// UnmarshalJSON implements the json.Unmarshaler interface for *nullBool.
func (nb *nullBool) UnmarshalJSON(b []byte) (err error) {
if len(b) == 0 || bytes.Equal(b, []byte("null")) {
*nb = nbNull
} else if bytes.Equal(b, []byte("true")) {
*nb = nbTrue
} else if bytes.Equal(b, []byte("false")) {
*nb = nbFalse
} else {
return fmt.Errorf("invalid nullBool value %q", b)
}
return nil
}

View File

@ -12,6 +12,7 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp" "github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
"github.com/AdguardTeam/AdGuardHome/internal/aghnet" "github.com/AdguardTeam/AdGuardHome/internal/aghnet"
"github.com/AdguardTeam/AdGuardHome/internal/updater" "github.com/AdguardTeam/AdGuardHome/internal/updater"
@ -147,8 +148,8 @@ type versionResponse struct {
// setAllowedToAutoUpdate sets CanAutoUpdate to true if AdGuard Home is actually // setAllowedToAutoUpdate sets CanAutoUpdate to true if AdGuard Home is actually
// allowed to perform an automatic update by the OS. // allowed to perform an automatic update by the OS.
func (vr *versionResponse) setAllowedToAutoUpdate() (err error) { func (vr *versionResponse) setAllowedToAutoUpdate() (err error) {
if vr.CanAutoUpdate == nil || !*vr.CanAutoUpdate { if vr.CanAutoUpdate != aghalg.NBTrue {
return return nil
} }
tlsConf := &tlsConfigSettings{} tlsConf := &tlsConfigSettings{}
@ -162,7 +163,7 @@ func (vr *versionResponse) setAllowedToAutoUpdate() (err error) {
} }
} }
vr.CanAutoUpdate = &canUpdate vr.CanAutoUpdate = aghalg.BoolToNullBool(canUpdate)
return nil return nil
} }

View File

@ -5,9 +5,9 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"strings"
"time" "time"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghio" "github.com/AdguardTeam/AdGuardHome/internal/aghio"
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
) )
@ -17,11 +17,12 @@ const versionCheckPeriod = 8 * time.Hour
// VersionInfo contains information about a new version. // VersionInfo contains information about a new version.
type VersionInfo struct { type VersionInfo struct {
CanAutoUpdate *bool `json:"can_autoupdate,omitempty"` NewVersion string `json:"new_version,omitempty"`
NewVersion string `json:"new_version,omitempty"` Announcement string `json:"announcement,omitempty"`
Announcement string `json:"announcement,omitempty"` AnnouncementURL string `json:"announcement_url,omitempty"`
AnnouncementURL string `json:"announcement_url,omitempty"` // TODO(a.garipov): See if the frontend actually still cares about
SelfUpdateMinVersion string `json:"-"` // nullability.
CanAutoUpdate aghalg.NullBool `json:"can_autoupdate,omitempty"`
} }
// MaxResponseSize is responses on server's requests maximum length in bytes. // MaxResponseSize is responses on server's requests maximum length in bytes.
@ -67,15 +68,13 @@ func (u *Updater) VersionInfo(forceRecheck bool) (vi VersionInfo, err error) {
} }
func (u *Updater) parseVersionResponse(data []byte) (VersionInfo, error) { func (u *Updater) parseVersionResponse(data []byte) (VersionInfo, error) {
var canAutoUpdate bool
info := VersionInfo{ info := VersionInfo{
CanAutoUpdate: &canAutoUpdate, CanAutoUpdate: aghalg.NBFalse,
} }
versionJSON := map[string]string{ versionJSON := map[string]string{
"version": "", "version": "",
"announcement": "", "announcement": "",
"announcement_url": "", "announcement_url": "",
"selfupdate_min_version": "",
} }
err := json.Unmarshal(data, &versionJSON) err := json.Unmarshal(data, &versionJSON)
if err != nil { if err != nil {
@ -91,14 +90,9 @@ func (u *Updater) parseVersionResponse(data []byte) (VersionInfo, error) {
info.NewVersion = versionJSON["version"] info.NewVersion = versionJSON["version"]
info.Announcement = versionJSON["announcement"] info.Announcement = versionJSON["announcement"]
info.AnnouncementURL = versionJSON["announcement_url"] info.AnnouncementURL = versionJSON["announcement_url"]
info.SelfUpdateMinVersion = versionJSON["selfupdate_min_version"]
packageURL, ok := u.downloadURL(versionJSON) packageURL, ok := u.downloadURL(versionJSON)
if ok && info.CanAutoUpdate = aghalg.BoolToNullBool(ok && info.NewVersion != u.version)
info.NewVersion != u.version &&
strings.TrimPrefix(u.version, "v") >= strings.TrimPrefix(info.SelfUpdateMinVersion, "v") {
canAutoUpdate = true
}
u.newVersion = info.NewVersion u.newVersion = info.NewVersion
u.packageURL = packageURL u.packageURL = packageURL

View File

@ -104,11 +104,14 @@ func NewUpdater(conf *Config) *Updater {
} }
// Update performs the auto-update. // Update performs the auto-update.
func (u *Updater) Update() error { func (u *Updater) Update() (err error) {
u.mu.Lock() u.mu.Lock()
defer u.mu.Unlock() defer u.mu.Unlock()
err := u.prepare() log.Info("updater: updating")
defer func() { log.Info("updater: finished; errors: %v", err) }()
err = u.prepare()
if err != nil { if err != nil {
return err return err
} }
@ -178,7 +181,12 @@ func (u *Updater) prepare() (err error) {
u.backupExeName = filepath.Join(u.backupDir, exeName) u.backupExeName = filepath.Join(u.backupDir, exeName)
u.updateExeName = filepath.Join(u.updateDir, exeName) u.updateExeName = filepath.Join(u.updateDir, exeName)
log.Info("Updating from %s to %s. URL:%s", version.Version(), u.newVersion, u.packageURL) log.Debug(
"updater: updating from %s to %s using url: %s",
version.Version(),
u.newVersion,
u.packageURL,
)
// TODO(a.garipov): Use os.Args[0] instead? // TODO(a.garipov): Use os.Args[0] instead?
u.currentExeName = filepath.Join(u.workDir, exeName) u.currentExeName = filepath.Join(u.workDir, exeName)
@ -194,7 +202,7 @@ func (u *Updater) unpack() error {
var err error var err error
_, pkgNameOnly := filepath.Split(u.packageURL) _, pkgNameOnly := filepath.Split(u.packageURL)
log.Debug("updater: unpacking the package") log.Debug("updater: unpacking package")
if strings.HasSuffix(pkgNameOnly, ".zip") { if strings.HasSuffix(pkgNameOnly, ".zip") {
u.unpackedFiles, err = zipFileUnpack(u.packageName, u.updateDir) u.unpackedFiles, err = zipFileUnpack(u.packageName, u.updateDir)
if err != nil { if err != nil {
@ -229,7 +237,7 @@ func (u *Updater) check() error {
} }
func (u *Updater) backup() error { func (u *Updater) backup() error {
log.Debug("updater: backing up the current configuration") log.Debug("updater: backing up current configuration")
_ = os.Mkdir(u.backupDir, 0o755) _ = os.Mkdir(u.backupDir, 0o755)
err := copyFile(u.confName, filepath.Join(u.backupDir, "AdGuardHome.yaml")) err := copyFile(u.confName, filepath.Join(u.backupDir, "AdGuardHome.yaml"))
if err != nil { if err != nil {
@ -252,7 +260,7 @@ func (u *Updater) replace() error {
return fmt.Errorf("copySupportingFiles(%s, %s) failed: %s", u.updateDir, u.workDir, err) return fmt.Errorf("copySupportingFiles(%s, %s) failed: %s", u.updateDir, u.workDir, err)
} }
log.Debug("updater: renaming: %s -> %s", u.currentExeName, u.backupExeName) log.Debug("updater: renaming: %s to %s", u.currentExeName, u.backupExeName)
err = os.Rename(u.currentExeName, u.backupExeName) err = os.Rename(u.currentExeName, u.backupExeName)
if err != nil { if err != nil {
return err return err
@ -268,7 +276,7 @@ func (u *Updater) replace() error {
return err return err
} }
log.Debug("updater: renamed: %s -> %s", u.updateExeName, u.currentExeName) log.Debug("updater: renamed: %s to %s", u.updateExeName, u.currentExeName)
return nil return nil
} }
@ -297,7 +305,7 @@ func (u *Updater) downloadPackageFile(url, filename string) (err error) {
return fmt.Errorf("http request failed: %w", err) return fmt.Errorf("http request failed: %w", err)
} }
log.Debug("updater: reading HTTP body") log.Debug("updater: reading http body")
// This use of ReadAll is now safe, because we limited body's Reader. // This use of ReadAll is now safe, because we limited body's Reader.
body, err := io.ReadAll(r) body, err := io.ReadAll(r)
if err != nil { if err != nil {
@ -343,7 +351,7 @@ func tarGzFileUnpackOne(outDir string, tr *tar.Reader, hdr *tar.Header) (name st
} }
if hdr.Typeflag != tar.TypeReg { if hdr.Typeflag != tar.TypeReg {
log.Debug("updater: %s: unknown file type %d, skipping", name, hdr.Typeflag) log.Info("updater: %s: unknown file type %d, skipping", name, hdr.Typeflag)
return "", nil return "", nil
} }
@ -364,7 +372,7 @@ func tarGzFileUnpackOne(outDir string, tr *tar.Reader, hdr *tar.Header) (name st
return "", fmt.Errorf("io.Copy(): %w", err) return "", fmt.Errorf("io.Copy(): %w", err)
} }
log.Tracef("updater: created file %s", outputName) log.Debug("updater: created file %q", outputName)
return name, nil return name, nil
} }
@ -440,7 +448,7 @@ func zipFileUnpackOne(outDir string, zf *zip.File) (name string, err error) {
return "", fmt.Errorf("os.Mkdir(%q): %w", outputName, err) return "", fmt.Errorf("os.Mkdir(%q): %w", outputName, err)
} }
log.Tracef("created directory %q", outputName) log.Debug("updater: created directory %q", outputName)
return "", nil return "", nil
} }
@ -457,7 +465,7 @@ func zipFileUnpackOne(outDir string, zf *zip.File) (name string, err error) {
return "", fmt.Errorf("io.Copy(): %w", err) return "", fmt.Errorf("io.Copy(): %w", err)
} }
log.Tracef("created file %s", outputName) log.Debug("updater: created file %q", outputName)
return name, nil return name, nil
} }
@ -516,7 +524,7 @@ func copySupportingFiles(files []string, srcdir, dstdir string) error {
return err return err
} }
log.Debug("updater: copied: %q -> %q", src, dst) log.Debug("updater: copied: %q to %q", src, dst)
} }
return nil return nil

View File

@ -10,6 +10,7 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
"github.com/AdguardTeam/AdGuardHome/internal/aghtest" "github.com/AdguardTeam/AdGuardHome/internal/aghtest"
"github.com/AdguardTeam/AdGuardHome/internal/version" "github.com/AdguardTeam/AdGuardHome/internal/version"
"github.com/AdguardTeam/golibs/testutil" "github.com/AdguardTeam/golibs/testutil"
@ -92,10 +93,7 @@ func TestUpdateGetVersion(t *testing.T) {
assert.Equal(t, "v0.103.0-beta.2", info.NewVersion) assert.Equal(t, "v0.103.0-beta.2", info.NewVersion)
assert.Equal(t, "AdGuard Home v0.103.0-beta.2 is now available!", info.Announcement) assert.Equal(t, "AdGuard Home v0.103.0-beta.2 is now available!", info.Announcement)
assert.Equal(t, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL) assert.Equal(t, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL)
assert.Equal(t, "v0.0", info.SelfUpdateMinVersion) assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate)
if assert.NotNil(t, info.CanAutoUpdate) {
assert.True(t, *info.CanAutoUpdate)
}
// check cached // check cached
_, err = u.VersionInfo(false) _, err = u.VersionInfo(false)
@ -290,10 +288,7 @@ func TestUpdater_VersionInto_ARM(t *testing.T) {
assert.Equal(t, "v0.103.0-beta.2", info.NewVersion) assert.Equal(t, "v0.103.0-beta.2", info.NewVersion)
assert.Equal(t, "AdGuard Home v0.103.0-beta.2 is now available!", info.Announcement) assert.Equal(t, "AdGuard Home v0.103.0-beta.2 is now available!", info.Announcement)
assert.Equal(t, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL) assert.Equal(t, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL)
assert.Equal(t, "v0.0", info.SelfUpdateMinVersion) assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate)
if assert.NotNil(t, info.CanAutoUpdate) {
assert.True(t, *info.CanAutoUpdate)
}
} }
func TestUpdater_VersionInto_MIPS(t *testing.T) { func TestUpdater_VersionInto_MIPS(t *testing.T) {
@ -330,8 +325,5 @@ func TestUpdater_VersionInto_MIPS(t *testing.T) {
assert.Equal(t, "v0.103.0-beta.2", info.NewVersion) assert.Equal(t, "v0.103.0-beta.2", info.NewVersion)
assert.Equal(t, "AdGuard Home v0.103.0-beta.2 is now available!", info.Announcement) assert.Equal(t, "AdGuard Home v0.103.0-beta.2 is now available!", info.Announcement)
assert.Equal(t, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL) assert.Equal(t, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL)
assert.Equal(t, "v0.0", info.SelfUpdateMinVersion) assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate)
if assert.NotNil(t, info.CanAutoUpdate) {
assert.True(t, *info.CanAutoUpdate)
}
} }

View File

@ -363,6 +363,7 @@ else
fi fi
readonly announcement_url readonly announcement_url
# TODO(a.garipov): Remove "selfupdate_min_version" in future versions.
rm -f "$version_json" rm -f "$version_json"
echo "{ echo "{
\"version\": \"${version}\", \"version\": \"${version}\",