Compare commits
No commits in common. "d3f39b0aa168ddf89755e769a1477ae3c91ece3a" and "3ce04f48ca01e9fe4e1344e5baaac0b15fd68585" have entirely different histories.
d3f39b0aa1
...
3ce04f48ca
64
CHANGELOG.md
64
CHANGELOG.md
@ -12,52 +12,24 @@ and this project adheres to
|
||||
## [Unreleased]
|
||||
|
||||
<!--
|
||||
## [v0.108.0] - 2022-10-01 (APPROX.)
|
||||
## [v0.108.0] - 2022-07-01 (APPROX.)
|
||||
-->
|
||||
|
||||
### 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
|
||||
[CVE-2022-29526], [CVE-2022-30634], [CVE-2022-30629], [CVE-2022-30580], and
|
||||
[CVE-2022-29804] vulnerabilities.
|
||||
- Enforced password strength policy ([#3503]).
|
||||
- Weaker cipher suites that use the CBC (cipher block chaining) mode of
|
||||
operation have been disabled ([#2993]).
|
||||
|
||||
### Added
|
||||
|
||||
- Support for the final DNS-over-QUIC standard, [RFC 9250][rfc-9250] ([#4592]).
|
||||
- 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
|
||||
`clients.runtime_sources` configuration object ([#3020]).
|
||||
- The ability to customize the set of networks that are considered private
|
||||
@ -69,6 +41,7 @@ See also the [v0.107.7 GitHub milestone][ms-v0.107.7].
|
||||
([#4166]).
|
||||
- Logs are now collected by default on FreeBSD and OpenBSD when AdGuard Home is
|
||||
installed as a service ([#4213]).
|
||||
- `windows/arm64` support ([#3057]).
|
||||
|
||||
### Changed
|
||||
|
||||
@ -152,9 +125,10 @@ In this release, the schema version has changed from 12 to 14.
|
||||
|
||||
### 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
|
||||
the flag completely.
|
||||
- Go 1.17 support. v0.109.0 will require at least Go 1.18 to build.
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -166,7 +140,9 @@ In this release, the schema version has changed from 12 to 14.
|
||||
- ARP tables refreshing process causing excessive PTR requests ([#3157]).
|
||||
|
||||
[#1730]: https://github.com/AdguardTeam/AdGuardHome/issues/1730
|
||||
[#2993]: https://github.com/AdguardTeam/AdGuardHome/issues/2993
|
||||
[#3020]: https://github.com/AdguardTeam/AdGuardHome/issues/3020
|
||||
[#3057]: https://github.com/AdguardTeam/AdGuardHome/issues/3057
|
||||
[#3142]: https://github.com/AdguardTeam/AdGuardHome/issues/3142
|
||||
[#3157]: https://github.com/AdguardTeam/AdGuardHome/issues/3157
|
||||
[#3367]: https://github.com/AdguardTeam/AdGuardHome/issues/3367
|
||||
@ -193,10 +169,20 @@ 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-30629]: https://www.cvedetails.com/cve/CVE-2022-30629
|
||||
[CVE-2022-30634]: https://www.cvedetails.com/cve/CVE-2022-30634
|
||||
[ms-v0.107.7]: https://github.com/AdguardTeam/AdGuardHome/milestone/43?closed=1
|
||||
[ddr-draft-06]: https://www.ietf.org/archive/id/draft-ietf-add-ddr-06.html
|
||||
[repr]: https://reproducible-builds.org/docs/source-date-epoch/
|
||||
[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
|
||||
|
||||
@ -248,7 +234,6 @@ See also the [v0.107.6 GitHub milestone][ms-v0.107.6].
|
||||
[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
|
||||
[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
|
||||
|
||||
|
||||
@ -1010,12 +995,11 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
|
||||
|
||||
|
||||
<!--
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.8...HEAD
|
||||
[v0.107.8]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.7...v0.107.8
|
||||
-->
|
||||
|
||||
[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
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.6...HEAD
|
||||
[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.4]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.3...v0.107.4
|
||||
|
||||
@ -445,7 +445,7 @@
|
||||
"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_settings_saved": "Access settings successfully saved",
|
||||
"updates_checked": "A new version of AdGuard Home is available",
|
||||
"updates_checked": "Updates successfully checked",
|
||||
"updates_version_equal": "AdGuard Home is up-to-date",
|
||||
"check_updates_now": "Check for updates now",
|
||||
"dns_privacy": "DNS Privacy",
|
||||
|
||||
@ -24,7 +24,6 @@ export const getTlsStatus = () => async (dispatch) => {
|
||||
export const setTlsConfigRequest = createAction('SET_TLS_CONFIG_REQUEST');
|
||||
export const setTlsConfigFailure = createAction('SET_TLS_CONFIG_FAILURE');
|
||||
export const setTlsConfigSuccess = createAction('SET_TLS_CONFIG_SUCCESS');
|
||||
export const dnsStatusSuccess = createAction('DNS_STATUS_SUCCESS');
|
||||
|
||||
export const setTlsConfig = (config) => async (dispatch, getState) => {
|
||||
dispatch(setTlsConfigRequest());
|
||||
@ -40,12 +39,6 @@ export const setTlsConfig = (config) => async (dispatch, getState) => {
|
||||
const response = await apiClient.setTlsConfig(values);
|
||||
response.certificate_chain = atob(response.certificate_chain);
|
||||
response.private_key = atob(response.private_key);
|
||||
|
||||
const dnsStatus = await apiClient.getGlobalStatus();
|
||||
if (dnsStatus) {
|
||||
dispatch(dnsStatusSuccess(dnsStatus));
|
||||
}
|
||||
|
||||
dispatch(setTlsConfigSuccess(response));
|
||||
dispatch(addSuccessToast('encryption_config_saved'));
|
||||
redirectToCurrentProtocol(response, httpPort);
|
||||
|
||||
@ -29,8 +29,6 @@ class Table extends Component {
|
||||
Header: this.props.t('actions_table_header'),
|
||||
accessor: 'actions',
|
||||
maxWidth: 100,
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
Cell: (value) => (
|
||||
<div className="logs__row logs__row--center">
|
||||
<button
|
||||
|
||||
@ -36,7 +36,6 @@ class Table extends Component {
|
||||
Cell: this.renderCheckbox,
|
||||
width: 90,
|
||||
className: 'text-center',
|
||||
resizable: false,
|
||||
},
|
||||
{
|
||||
Header: <Trans>name_table_header</Trans>,
|
||||
@ -78,11 +77,10 @@ class Table extends Component {
|
||||
},
|
||||
{
|
||||
Header: <Trans>actions_table_header</Trans>,
|
||||
accessor: 'actions',
|
||||
accessor: 'url',
|
||||
className: 'text-center',
|
||||
width: 100,
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
Cell: (row) => {
|
||||
const { value } = row;
|
||||
const { t, toggleFilteringModal, handleDelete } = this.props;
|
||||
|
||||
@ -338,19 +338,10 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.logs__row--icons {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.logs__table .logs__row {
|
||||
border-bottom: 2px solid var(--gray-216);
|
||||
}
|
||||
|
||||
.logs__tag {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* QUERY_STATUS_COLORS */
|
||||
.logs__row--blue {
|
||||
background-color: var(--blue);
|
||||
|
||||
@ -193,7 +193,7 @@ class ClientsTable extends Component {
|
||||
<div className="logs__row o-hidden">
|
||||
<span className="logs__text">
|
||||
{value.map((tag) => (
|
||||
<div key={tag} title={tag} className="logs__tag small">
|
||||
<div key={tag} title={tag} className="small">
|
||||
{tag}
|
||||
</div>
|
||||
))}
|
||||
@ -225,8 +225,6 @@ class ClientsTable extends Component {
|
||||
Header: this.props.t('actions_table_header'),
|
||||
accessor: 'actions',
|
||||
maxWidth: 100,
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
Cell: (row) => {
|
||||
const clientName = row.original.name;
|
||||
const {
|
||||
|
||||
@ -70,8 +70,6 @@ const StaticLeases = ({
|
||||
Header: <Trans>actions_table_header</Trans>,
|
||||
accessor: 'actions',
|
||||
maxWidth: 150,
|
||||
sortable: false,
|
||||
resizable: false,
|
||||
// eslint-disable-next-line react/display-name
|
||||
Cell: (row) => {
|
||||
const { ip, mac, hostname } = row.original;
|
||||
|
||||
@ -113,7 +113,6 @@
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-color: transparent;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-icon--green {
|
||||
|
||||
@ -1,59 +0,0 @@
|
||||
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
|
||||
}
|
||||
@ -10,7 +10,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
@ -146,7 +145,7 @@ type dhcpServerConfigJSON struct {
|
||||
V4 *v4ServerConfJSON `json:"v4"`
|
||||
V6 *v6ServerConfJSON `json:"v6"`
|
||||
InterfaceName string `json:"interface_name"`
|
||||
Enabled aghalg.NullBool `json:"enabled"`
|
||||
Enabled nullBool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (s *Server) handleDHCPSetConfigV4(
|
||||
@ -157,7 +156,7 @@ func (s *Server) handleDHCPSetConfigV4(
|
||||
}
|
||||
|
||||
v4Conf := v4JSONToServerConf(conf.V4)
|
||||
v4Conf.Enabled = conf.Enabled == aghalg.NBTrue
|
||||
v4Conf.Enabled = conf.Enabled == nbTrue
|
||||
if len(v4Conf.RangeStart) == 0 {
|
||||
v4Conf.Enabled = false
|
||||
}
|
||||
@ -184,7 +183,7 @@ func (s *Server) handleDHCPSetConfigV6(
|
||||
}
|
||||
|
||||
v6Conf := v6JSONToServerConf(conf.V6)
|
||||
v6Conf.Enabled = conf.Enabled == aghalg.NBTrue
|
||||
v6Conf.Enabled = conf.Enabled == nbTrue
|
||||
if len(v6Conf.RangeStart) == 0 {
|
||||
v6Conf.Enabled = false
|
||||
}
|
||||
@ -207,7 +206,7 @@ func (s *Server) handleDHCPSetConfigV6(
|
||||
|
||||
func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
conf := &dhcpServerConfigJSON{}
|
||||
conf.Enabled = aghalg.BoolToNullBool(s.conf.Enabled)
|
||||
conf.Enabled = boolToNullBool(s.conf.Enabled)
|
||||
conf.InterfaceName = s.conf.InterfaceName
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(conf)
|
||||
@ -231,7 +230,7 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if conf.Enabled == aghalg.NBTrue && !v4Enabled && !v6Enabled {
|
||||
if conf.Enabled == nbTrue && !v4Enabled && !v6Enabled {
|
||||
aghhttp.Error(r, w, http.StatusBadRequest, "dhcpv4 or dhcpv6 configuration must be complete")
|
||||
|
||||
return
|
||||
@ -244,8 +243,8 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if conf.Enabled != aghalg.NBNull {
|
||||
s.conf.Enabled = conf.Enabled == aghalg.NBTrue
|
||||
if conf.Enabled != nbNull {
|
||||
s.conf.Enabled = conf.Enabled == nbTrue
|
||||
}
|
||||
|
||||
if conf.InterfaceName != "" {
|
||||
@ -280,11 +279,11 @@ func (s *Server) handleDHCPSetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
type netInterfaceJSON struct {
|
||||
Name string `json:"name"`
|
||||
HardwareAddr string `json:"hardware_address"`
|
||||
Flags string `json:"flags"`
|
||||
GatewayIP net.IP `json:"gateway_ip"`
|
||||
HardwareAddr string `json:"hardware_address"`
|
||||
Addrs4 []net.IP `json:"ipv4_addresses"`
|
||||
Addrs6 []net.IP `json:"ipv6_addresses"`
|
||||
Flags string `json:"flags"`
|
||||
}
|
||||
|
||||
func (s *Server) handleDHCPInterfaces(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
58
internal/dhcpd/nullbool.go
Normal file
58
internal/dhcpd/nullbool.go
Normal file
@ -0,0 +1,58 @@
|
||||
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
|
||||
}
|
||||
@ -1,10 +1,9 @@
|
||||
package aghalg_test
|
||||
package dhcpd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -15,37 +14,37 @@ func TestNullBool_UnmarshalJSON(t *testing.T) {
|
||||
name string
|
||||
wantErrMsg string
|
||||
data []byte
|
||||
want aghalg.NullBool
|
||||
want nullBool
|
||||
}{{
|
||||
name: "empty",
|
||||
wantErrMsg: "",
|
||||
data: []byte{},
|
||||
want: aghalg.NBNull,
|
||||
want: nbNull,
|
||||
}, {
|
||||
name: "null",
|
||||
wantErrMsg: "",
|
||||
data: []byte("null"),
|
||||
want: aghalg.NBNull,
|
||||
want: nbNull,
|
||||
}, {
|
||||
name: "true",
|
||||
wantErrMsg: "",
|
||||
data: []byte("true"),
|
||||
want: aghalg.NBTrue,
|
||||
want: nbTrue,
|
||||
}, {
|
||||
name: "false",
|
||||
wantErrMsg: "",
|
||||
data: []byte("false"),
|
||||
want: aghalg.NBFalse,
|
||||
want: nbFalse,
|
||||
}, {
|
||||
name: "invalid",
|
||||
wantErrMsg: `unmarshalling json data into aghalg.NullBool: bad value "invalid"`,
|
||||
wantErrMsg: `invalid nullBool value "invalid"`,
|
||||
data: []byte("invalid"),
|
||||
want: aghalg.NBNull,
|
||||
want: nbNull,
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var got aghalg.NullBool
|
||||
var got nullBool
|
||||
err := got.UnmarshalJSON(tc.data)
|
||||
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
|
||||
|
||||
@ -54,9 +53,9 @@ func TestNullBool_UnmarshalJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("json", func(t *testing.T) {
|
||||
want := aghalg.NBTrue
|
||||
want := nbTrue
|
||||
var got struct {
|
||||
A aghalg.NullBool
|
||||
A nullBool
|
||||
}
|
||||
|
||||
err := json.Unmarshal([]byte(`{"A":true}`), &got)
|
||||
@ -12,7 +12,6 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/updater"
|
||||
@ -148,8 +147,8 @@ type versionResponse struct {
|
||||
// setAllowedToAutoUpdate sets CanAutoUpdate to true if AdGuard Home is actually
|
||||
// allowed to perform an automatic update by the OS.
|
||||
func (vr *versionResponse) setAllowedToAutoUpdate() (err error) {
|
||||
if vr.CanAutoUpdate != aghalg.NBTrue {
|
||||
return nil
|
||||
if vr.CanAutoUpdate == nil || !*vr.CanAutoUpdate {
|
||||
return
|
||||
}
|
||||
|
||||
tlsConf := &tlsConfigSettings{}
|
||||
@ -163,7 +162,7 @@ func (vr *versionResponse) setAllowedToAutoUpdate() (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
vr.CanAutoUpdate = aghalg.BoolToNullBool(canUpdate)
|
||||
vr.CanAutoUpdate = &canUpdate
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -5,9 +5,9 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghio"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
)
|
||||
@ -17,12 +17,11 @@ const versionCheckPeriod = 8 * time.Hour
|
||||
|
||||
// VersionInfo contains information about a new version.
|
||||
type VersionInfo struct {
|
||||
CanAutoUpdate *bool `json:"can_autoupdate,omitempty"`
|
||||
NewVersion string `json:"new_version,omitempty"`
|
||||
Announcement string `json:"announcement,omitempty"`
|
||||
AnnouncementURL string `json:"announcement_url,omitempty"`
|
||||
// TODO(a.garipov): See if the frontend actually still cares about
|
||||
// nullability.
|
||||
CanAutoUpdate aghalg.NullBool `json:"can_autoupdate,omitempty"`
|
||||
SelfUpdateMinVersion string `json:"-"`
|
||||
}
|
||||
|
||||
// MaxResponseSize is responses on server's requests maximum length in bytes.
|
||||
@ -68,13 +67,15 @@ func (u *Updater) VersionInfo(forceRecheck bool) (vi VersionInfo, err error) {
|
||||
}
|
||||
|
||||
func (u *Updater) parseVersionResponse(data []byte) (VersionInfo, error) {
|
||||
var canAutoUpdate bool
|
||||
info := VersionInfo{
|
||||
CanAutoUpdate: aghalg.NBFalse,
|
||||
CanAutoUpdate: &canAutoUpdate,
|
||||
}
|
||||
versionJSON := map[string]string{
|
||||
"version": "",
|
||||
"announcement": "",
|
||||
"announcement_url": "",
|
||||
"selfupdate_min_version": "",
|
||||
}
|
||||
err := json.Unmarshal(data, &versionJSON)
|
||||
if err != nil {
|
||||
@ -90,9 +91,14 @@ func (u *Updater) parseVersionResponse(data []byte) (VersionInfo, error) {
|
||||
info.NewVersion = versionJSON["version"]
|
||||
info.Announcement = versionJSON["announcement"]
|
||||
info.AnnouncementURL = versionJSON["announcement_url"]
|
||||
info.SelfUpdateMinVersion = versionJSON["selfupdate_min_version"]
|
||||
|
||||
packageURL, ok := u.downloadURL(versionJSON)
|
||||
info.CanAutoUpdate = aghalg.BoolToNullBool(ok && info.NewVersion != u.version)
|
||||
if ok &&
|
||||
info.NewVersion != u.version &&
|
||||
strings.TrimPrefix(u.version, "v") >= strings.TrimPrefix(info.SelfUpdateMinVersion, "v") {
|
||||
canAutoUpdate = true
|
||||
}
|
||||
|
||||
u.newVersion = info.NewVersion
|
||||
u.packageURL = packageURL
|
||||
|
||||
@ -104,14 +104,11 @@ func NewUpdater(conf *Config) *Updater {
|
||||
}
|
||||
|
||||
// Update performs the auto-update.
|
||||
func (u *Updater) Update() (err error) {
|
||||
func (u *Updater) Update() error {
|
||||
u.mu.Lock()
|
||||
defer u.mu.Unlock()
|
||||
|
||||
log.Info("updater: updating")
|
||||
defer func() { log.Info("updater: finished; errors: %v", err) }()
|
||||
|
||||
err = u.prepare()
|
||||
err := u.prepare()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -181,12 +178,7 @@ func (u *Updater) prepare() (err error) {
|
||||
u.backupExeName = filepath.Join(u.backupDir, exeName)
|
||||
u.updateExeName = filepath.Join(u.updateDir, exeName)
|
||||
|
||||
log.Debug(
|
||||
"updater: updating from %s to %s using url: %s",
|
||||
version.Version(),
|
||||
u.newVersion,
|
||||
u.packageURL,
|
||||
)
|
||||
log.Info("Updating from %s to %s. URL:%s", version.Version(), u.newVersion, u.packageURL)
|
||||
|
||||
// TODO(a.garipov): Use os.Args[0] instead?
|
||||
u.currentExeName = filepath.Join(u.workDir, exeName)
|
||||
@ -202,7 +194,7 @@ func (u *Updater) unpack() error {
|
||||
var err error
|
||||
_, pkgNameOnly := filepath.Split(u.packageURL)
|
||||
|
||||
log.Debug("updater: unpacking package")
|
||||
log.Debug("updater: unpacking the package")
|
||||
if strings.HasSuffix(pkgNameOnly, ".zip") {
|
||||
u.unpackedFiles, err = zipFileUnpack(u.packageName, u.updateDir)
|
||||
if err != nil {
|
||||
@ -237,7 +229,7 @@ func (u *Updater) check() error {
|
||||
}
|
||||
|
||||
func (u *Updater) backup() error {
|
||||
log.Debug("updater: backing up current configuration")
|
||||
log.Debug("updater: backing up the current configuration")
|
||||
_ = os.Mkdir(u.backupDir, 0o755)
|
||||
err := copyFile(u.confName, filepath.Join(u.backupDir, "AdGuardHome.yaml"))
|
||||
if err != nil {
|
||||
@ -260,7 +252,7 @@ func (u *Updater) replace() error {
|
||||
return fmt.Errorf("copySupportingFiles(%s, %s) failed: %s", u.updateDir, u.workDir, err)
|
||||
}
|
||||
|
||||
log.Debug("updater: renaming: %s to %s", u.currentExeName, u.backupExeName)
|
||||
log.Debug("updater: renaming: %s -> %s", u.currentExeName, u.backupExeName)
|
||||
err = os.Rename(u.currentExeName, u.backupExeName)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -276,7 +268,7 @@ func (u *Updater) replace() error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug("updater: renamed: %s to %s", u.updateExeName, u.currentExeName)
|
||||
log.Debug("updater: renamed: %s -> %s", u.updateExeName, u.currentExeName)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -305,7 +297,7 @@ func (u *Updater) downloadPackageFile(url, filename string) (err error) {
|
||||
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.
|
||||
body, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
@ -351,7 +343,7 @@ func tarGzFileUnpackOne(outDir string, tr *tar.Reader, hdr *tar.Header) (name st
|
||||
}
|
||||
|
||||
if hdr.Typeflag != tar.TypeReg {
|
||||
log.Info("updater: %s: unknown file type %d, skipping", name, hdr.Typeflag)
|
||||
log.Debug("updater: %s: unknown file type %d, skipping", name, hdr.Typeflag)
|
||||
|
||||
return "", nil
|
||||
}
|
||||
@ -372,7 +364,7 @@ func tarGzFileUnpackOne(outDir string, tr *tar.Reader, hdr *tar.Header) (name st
|
||||
return "", fmt.Errorf("io.Copy(): %w", err)
|
||||
}
|
||||
|
||||
log.Debug("updater: created file %q", outputName)
|
||||
log.Tracef("updater: created file %s", outputName)
|
||||
|
||||
return name, nil
|
||||
}
|
||||
@ -448,7 +440,7 @@ func zipFileUnpackOne(outDir string, zf *zip.File) (name string, err error) {
|
||||
return "", fmt.Errorf("os.Mkdir(%q): %w", outputName, err)
|
||||
}
|
||||
|
||||
log.Debug("updater: created directory %q", outputName)
|
||||
log.Tracef("created directory %q", outputName)
|
||||
|
||||
return "", nil
|
||||
}
|
||||
@ -465,7 +457,7 @@ func zipFileUnpackOne(outDir string, zf *zip.File) (name string, err error) {
|
||||
return "", fmt.Errorf("io.Copy(): %w", err)
|
||||
}
|
||||
|
||||
log.Debug("updater: created file %q", outputName)
|
||||
log.Tracef("created file %s", outputName)
|
||||
|
||||
return name, nil
|
||||
}
|
||||
@ -524,7 +516,7 @@ func copySupportingFiles(files []string, srcdir, dstdir string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug("updater: copied: %q to %q", src, dst)
|
||||
log.Debug("updater: copied: %q -> %q", src, dst)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@ -10,7 +10,6 @@ import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghalg"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtest"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
@ -93,7 +92,10 @@ func TestUpdateGetVersion(t *testing.T) {
|
||||
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, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL)
|
||||
assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate)
|
||||
assert.Equal(t, "v0.0", info.SelfUpdateMinVersion)
|
||||
if assert.NotNil(t, info.CanAutoUpdate) {
|
||||
assert.True(t, *info.CanAutoUpdate)
|
||||
}
|
||||
|
||||
// check cached
|
||||
_, err = u.VersionInfo(false)
|
||||
@ -288,7 +290,10 @@ func TestUpdater_VersionInto_ARM(t *testing.T) {
|
||||
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, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL)
|
||||
assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate)
|
||||
assert.Equal(t, "v0.0", info.SelfUpdateMinVersion)
|
||||
if assert.NotNil(t, info.CanAutoUpdate) {
|
||||
assert.True(t, *info.CanAutoUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdater_VersionInto_MIPS(t *testing.T) {
|
||||
@ -325,5 +330,8 @@ func TestUpdater_VersionInto_MIPS(t *testing.T) {
|
||||
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, "https://github.com/AdguardTeam/AdGuardHome/internal/releases", info.AnnouncementURL)
|
||||
assert.Equal(t, aghalg.NBTrue, info.CanAutoUpdate)
|
||||
assert.Equal(t, "v0.0", info.SelfUpdateMinVersion)
|
||||
if assert.NotNil(t, info.CanAutoUpdate) {
|
||||
assert.True(t, *info.CanAutoUpdate)
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,7 +363,6 @@ else
|
||||
fi
|
||||
readonly announcement_url
|
||||
|
||||
# TODO(a.garipov): Remove "selfupdate_min_version" in future versions.
|
||||
rm -f "$version_json"
|
||||
echo "{
|
||||
\"version\": \"${version}\",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user