mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2026-08-27 20:35:40 +00:00
Pull request 2713: AGDNS-4240-install-lang
Squashed commit of the following: commit 1baf3ec81abb8f90cc2e9789945d1c10fcc23225 Merge: f8eaf24cb4d0ae0d87Author: Ainar Garipov <a.garipov@adguard.com> Date: Wed Jul 15 13:18:02 2026 +0300 Merge branch 'master' into AGDNS-4240-install-lang commit f8eaf24cbe91bdf825b58be6b0b565310767c001 Author: Ainar Garipov <a.garipov@adguard.com> Date: Wed Jul 15 13:17:16 2026 +0300 openapi: imp language codes commitf811b3f5c2Author: Ainar Garipov <a.garipov@adguard.com> Date: Tue Jul 14 18:56:28 2026 +0300 home: use validation more commit7e8fd77aa8Author: Ainar Garipov <a.garipov@adguard.com> Date: Tue Jul 14 18:49:38 2026 +0300 home: fix copying install properties commit2178b01e9fAuthor: Ainar Garipov <a.garipov@adguard.com> Date: Tue Jul 14 18:43:07 2026 +0300 home: rm unnecessary validation commit407ef86aa9Author: Ainar Garipov <a.garipov@adguard.com> Date: Tue Jul 14 17:53:23 2026 +0300 home: add language to install api
This commit is contained in:
parent
4d0ae0d87b
commit
5b864cefc2
6 changed files with 122 additions and 30 deletions
|
|
@ -20,13 +20,15 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
|||
|
||||
### Added
|
||||
|
||||
- New property `"language"` in `POST /control/install/check_config` and `POST /control/install/configure` HTTP APIs.
|
||||
|
||||
- The user is able to remove the static lease's hostname via the HTTP API.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Blocked requests without an EDNS(0) OPT record ([#8183]).
|
||||
|
||||
[#8183]: https://github.com/AdguardTeam/AdGuardHome/issues/8183
|
||||
[#8183]: https://github.com/AdguardTeam/AdGuardHome/issues/8183
|
||||
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
|
|
|
|||
|
|
@ -84,9 +84,12 @@ type checkConfReqEnt struct {
|
|||
}
|
||||
|
||||
type checkConfReq struct {
|
||||
Web checkConfReqEnt `json:"web"`
|
||||
DNS checkConfReqEnt `json:"dns"`
|
||||
SetStaticIP bool `json:"set_static_ip"`
|
||||
Web checkConfReqEnt `json:"web"`
|
||||
DNS checkConfReqEnt `json:"dns"`
|
||||
|
||||
Language string `json:"language"`
|
||||
|
||||
SetStaticIP bool `json:"set_static_ip"`
|
||||
}
|
||||
|
||||
type checkConfRespEnt struct {
|
||||
|
|
@ -102,8 +105,9 @@ type staticIPJSON struct {
|
|||
|
||||
type checkConfResp struct {
|
||||
StaticIP staticIPJSON `json:"static_ip"`
|
||||
Web checkConfRespEnt `json:"web"`
|
||||
DNS checkConfRespEnt `json:"dns"`
|
||||
Language checkConfRespEnt `json:"language"`
|
||||
Web checkConfRespEnt `json:"web"`
|
||||
}
|
||||
|
||||
// validateWeb returns error is the web part if the initial configuration can't
|
||||
|
|
@ -200,6 +204,12 @@ func (web *webAPI) handleInstallCheckConfig(w http.ResponseWriter, r *http.Reque
|
|||
}
|
||||
|
||||
resp := &checkConfResp{}
|
||||
|
||||
err = validateLang(req.Language, true)
|
||||
if err != nil {
|
||||
resp.Language.Status = err.Error()
|
||||
}
|
||||
|
||||
tcpPorts := aghalg.UniqChecker[tcpPort]{}
|
||||
if err = req.validateWeb(tcpPorts); err != nil {
|
||||
resp.Web.Status = err.Error()
|
||||
|
|
@ -362,19 +372,21 @@ type applyConfigReqEnt struct {
|
|||
}
|
||||
|
||||
type applyConfigReq struct {
|
||||
Username string `json:"username"`
|
||||
Language string `json:"language"`
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username"`
|
||||
|
||||
Web applyConfigReqEnt `json:"web"`
|
||||
DNS applyConfigReqEnt `json:"dns"`
|
||||
}
|
||||
|
||||
// copyInstallSettings copies the installation parameters between two
|
||||
// configuration structures.
|
||||
// configuration structures. All arguments must not be nil.
|
||||
func copyInstallSettings(dst, src *configuration) {
|
||||
dst.HTTPConfig = src.HTTPConfig
|
||||
dst.DNS.BindHosts = src.DNS.BindHosts
|
||||
dst.DNS.Port = src.DNS.Port
|
||||
dst.HTTPConfig = src.HTTPConfig
|
||||
dst.Language = src.Language
|
||||
}
|
||||
|
||||
// shutdownTimeout is the timeout for shutting HTTP server down operation.
|
||||
|
|
@ -491,6 +503,10 @@ func (web *webAPI) finalizeInstall(
|
|||
}
|
||||
}()
|
||||
|
||||
if req.Language != "" {
|
||||
config.Language = req.Language
|
||||
}
|
||||
|
||||
config.DNS.BindHosts = []netip.Addr{req.DNS.IP}
|
||||
config.DNS.Port = req.DNS.Port
|
||||
config.Filtering.Logger = web.baseLogger.With(slogutil.KeyPrefix, "filtering")
|
||||
|
|
@ -589,6 +605,12 @@ func decodeApplyConfigReq(r io.Reader) (req *applyConfigReq, restartHTTP bool, e
|
|||
return nil, false, fmt.Errorf("parsing request: %w", err)
|
||||
}
|
||||
|
||||
err = validateLang(req.Language, true)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
if req.Web.Port == 0 || req.DNS.Port == 0 {
|
||||
return nil, false, errors.Error("ports cannot be 0")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package home
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghhttp"
|
||||
|
|
@ -48,6 +49,20 @@ var allowedLanguages = container.NewMapSet(
|
|||
"zh-tw",
|
||||
)
|
||||
|
||||
// validateLang returns a standard error about if lang is an unknown language.
|
||||
// If allowEmpty is true, the language can also be empty.
|
||||
func validateLang(lang string, allowEmpty bool) (err error) {
|
||||
if allowEmpty && lang == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !allowedLanguages.Has(lang) {
|
||||
return fmt.Errorf("unknown language: %q", lang)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// languageJSON is the JSON structure for language requests and responses.
|
||||
type languageJSON struct {
|
||||
Language string `json:"language"`
|
||||
|
|
@ -89,8 +104,9 @@ func (web *webAPI) handleI18nChangeLanguage(w http.ResponseWriter, r *http.Reque
|
|||
}
|
||||
|
||||
lang := langReq.Language
|
||||
if !allowedLanguages.Has(lang) {
|
||||
aghhttp.ErrorAndLog(ctx, l, r, w, http.StatusBadRequest, "unknown language: %q", lang)
|
||||
err = validateLang(lang, false)
|
||||
if err != nil {
|
||||
aghhttp.ErrorAndLog(ctx, l, r, w, http.StatusBadRequest, "%s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,8 +94,9 @@ func (web *webAPI) handlePutProfile(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
lang := profileReq.Language
|
||||
if !allowedLanguages.Has(lang) {
|
||||
aghhttp.ErrorAndLog(ctx, l, r, w, http.StatusBadRequest, "unknown language: %q", lang)
|
||||
err = validateLang(lang, false)
|
||||
if err != nil {
|
||||
aghhttp.ErrorAndLog(ctx, l, r, w, http.StatusBadRequest, "%s", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,13 @@
|
|||
|
||||
<!-- TODO(a.garipov): Reformat in accordance with the KeepAChangelog spec. -->
|
||||
|
||||
## v0.107.78: API changes
|
||||
## v0.107.79: API changes
|
||||
|
||||
### New `interval` values in `GET /control/filtering/status` and `POST /control/filtering/config` APIs
|
||||
### Setting the UI language through the install API
|
||||
|
||||
- New property `"language"` in `POST /control/install/check_config` and `POST /control/install/configure` HTTP APIs defines the language to use once AdGuard Home is installed.
|
||||
|
||||
## v0.107.78: API changes
|
||||
|
||||
The property `interval` of the objects returned from and accepted by the aforementioned APIs can now be any integer between 0 and 8760 (365 days).
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
'openapi': '3.0.3'
|
||||
'openapi': '3.2.0'
|
||||
'info':
|
||||
'title': 'AdGuard Home'
|
||||
'description': >
|
||||
|
|
@ -1543,8 +1543,7 @@
|
|||
'type': 'string'
|
||||
'example': 'v0.123.4'
|
||||
'language':
|
||||
'type': 'string'
|
||||
'example': 'en'
|
||||
'$ref': '#/components/schemas/Lang'
|
||||
'start_time':
|
||||
'type': 'number'
|
||||
'format': 'double'
|
||||
|
|
@ -2685,7 +2684,7 @@
|
|||
'name':
|
||||
'type': 'string'
|
||||
'language':
|
||||
'type': 'string'
|
||||
'$ref': '#/components/schemas/Lang'
|
||||
'theme':
|
||||
'type': 'string'
|
||||
'description': 'Interface theme'
|
||||
|
|
@ -3159,11 +3158,13 @@
|
|||
'properties':
|
||||
'dns':
|
||||
'$ref': '#/components/schemas/CheckConfigRequestInfo'
|
||||
'web':
|
||||
'$ref': '#/components/schemas/CheckConfigRequestInfo'
|
||||
'language':
|
||||
'$ref': '#/components/schemas/Lang'
|
||||
'set_static_ip':
|
||||
'type': 'boolean'
|
||||
'example': false
|
||||
'web':
|
||||
'$ref': '#/components/schemas/CheckConfigRequestInfo'
|
||||
'CheckConfigRequestInfo':
|
||||
'type': 'object'
|
||||
'properties':
|
||||
|
|
@ -3181,15 +3182,18 @@
|
|||
'type': 'object'
|
||||
'required':
|
||||
- 'dns'
|
||||
- 'web'
|
||||
- 'language'
|
||||
- 'static_ip'
|
||||
- 'web'
|
||||
'properties':
|
||||
'dns':
|
||||
'$ref': '#/components/schemas/CheckConfigResponseInfo'
|
||||
'web':
|
||||
'language':
|
||||
'$ref': '#/components/schemas/CheckConfigResponseInfo'
|
||||
'static_ip':
|
||||
'$ref': '#/components/schemas/CheckConfigStaticIpInfo'
|
||||
'web':
|
||||
'$ref': '#/components/schemas/CheckConfigResponseInfo'
|
||||
'CheckConfigResponseInfo':
|
||||
'type': 'object'
|
||||
'required':
|
||||
|
|
@ -3231,21 +3235,23 @@
|
|||
'required':
|
||||
- 'dns'
|
||||
- 'web'
|
||||
- 'username'
|
||||
- 'password'
|
||||
- 'username'
|
||||
'properties':
|
||||
'dns':
|
||||
'$ref': '#/components/schemas/AddressInfo'
|
||||
'web':
|
||||
'$ref': '#/components/schemas/AddressInfo'
|
||||
'username':
|
||||
'type': 'string'
|
||||
'description': 'Basic auth username'
|
||||
'example': 'admin'
|
||||
'language':
|
||||
'$ref': '#/components/schemas/Lang'
|
||||
'password':
|
||||
'type': 'string'
|
||||
'description': 'Basic auth password'
|
||||
'example': 'password'
|
||||
'type': 'string'
|
||||
'username':
|
||||
'description': 'Basic auth username'
|
||||
'example': 'admin'
|
||||
'type': 'string'
|
||||
'Login':
|
||||
'type': 'object'
|
||||
'description': 'Login request data'
|
||||
|
|
@ -3267,11 +3273,52 @@
|
|||
'description': 'Language settings object.'
|
||||
'properties':
|
||||
'language':
|
||||
'description': 'The current language or the language to set.'
|
||||
'type': 'string'
|
||||
'$ref': '#/components/schemas/Lang'
|
||||
'required':
|
||||
- 'language'
|
||||
'type': 'object'
|
||||
'Lang':
|
||||
'description': >
|
||||
Language code.
|
||||
# Hold the enum in sync with .twosky.json.
|
||||
'enum':
|
||||
- 'ar'
|
||||
- 'be'
|
||||
- 'bg'
|
||||
- 'cs'
|
||||
- 'da'
|
||||
- 'de'
|
||||
- 'en'
|
||||
- 'es'
|
||||
- 'fa'
|
||||
- 'fi'
|
||||
- 'fr'
|
||||
- 'hr'
|
||||
- 'hu'
|
||||
- 'id'
|
||||
- 'it'
|
||||
- 'ja'
|
||||
- 'ko'
|
||||
- 'nl'
|
||||
- 'no'
|
||||
- 'pl'
|
||||
- 'pt-br'
|
||||
- 'pt-pt'
|
||||
- 'ro'
|
||||
- 'ru'
|
||||
- 'si-lk'
|
||||
- 'sk'
|
||||
- 'sl'
|
||||
- 'sr-cs'
|
||||
- 'sv'
|
||||
- 'th'
|
||||
- 'tr'
|
||||
- 'uk'
|
||||
- 'vi'
|
||||
- 'zh-cn'
|
||||
- 'zh-hk'
|
||||
- 'zh-tw'
|
||||
'type': 'string'
|
||||
'securitySchemes':
|
||||
'basicAuth':
|
||||
'type': 'http'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue