diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 69082b94..46fc464d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,7 +1,7 @@ 'name': 'build' 'env': - 'GO_VERSION': '1.23.5' + 'GO_VERSION': '1.23.6' 'NODE_VERSION': '18' 'on': @@ -39,7 +39,7 @@ 'with': 'node-version': '${{ env.NODE_VERSION }}' - 'name': 'Set up Go modules cache' - 'uses': 'actions/cache@v2' + 'uses': 'actions/cache@v4' 'with': 'path': '~/go/pkg/mod' 'key': "${{ runner.os }}-go-${{ hashFiles('go.sum') }}" @@ -48,7 +48,7 @@ 'id': 'npm-cache' 'run': 'echo "::set-output name=dir::$( npm config get cache )"' - 'name': 'Set up npm cache' - 'uses': 'actions/cache@v2' + 'uses': 'actions/cache@v4' 'with': 'path': '${{ steps.npm-cache.outputs.dir }}' 'key': "${{ runner.os }}-node-${{ hashFiles('client/package-lock.json') }}" @@ -80,7 +80,7 @@ 'with': 'node-version': '${{ env.NODE_VERSION }}' - 'name': 'Set up Go modules cache' - 'uses': 'actions/cache@v2' + 'uses': 'actions/cache@v4' 'with': 'path': '~/go/pkg/mod' 'key': "${{ runner.os }}-go-${{ hashFiles('go.sum') }}" @@ -89,7 +89,7 @@ 'id': 'npm-cache' 'run': 'echo "::set-output name=dir::$(npm config get cache)"' - 'name': 'Set up npm cache' - 'uses': 'actions/cache@v2' + 'uses': 'actions/cache@v4' 'with': 'path': '${{ steps.npm-cache.outputs.dir }}' 'key': "${{ runner.os }}-node-${{ hashFiles('client/package-lock.json') }}" diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 735a3882..93d61c9a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,7 +1,7 @@ 'name': 'lint' 'env': - 'GO_VERSION': '1.23.5' + 'GO_VERSION': '1.23.6' 'on': 'push': diff --git a/.gitignore b/.gitignore index 5fd6dc60..a9598645 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,10 @@ /agh-backup/ /bin/ /build/* +/client/blob-report/ +/client/playwright-report/ +/client/playwright/.cache/ +/client/test-results/ /data/ /dist/ /filtering/tests/filtering.TestLotsOfRules*.pprof @@ -33,9 +37,5 @@ AdGuardHome.exe AdGuardHome.yaml* coverage.txt node_modules/ -/client/blob-report/ -/client/playwright-report/ -/client/playwright/.cache/ -/client/test-results/ !/build/gitkeep diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c216f35..b4866ada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,22 @@ See also the [v0.107.57 GitHub milestone][ms-v0.107.57]. NOTE: Add new changes BELOW THIS COMMENT. --> +### Security + +- Go version has been updated to prevent the possibility of exploiting the Go vulnerabilities fixed in [1.23.6][go-1.23.6]. + +### Changed + +- The *Fastest IP adddress* upstream mode now collects statistics for the all upstream DNS servers. + +### Fixed + +- The formatting of large numbers in the upstream table and query log ([#7590]). + +[#7590]: https://github.com/AdguardTeam/AdGuardHome/issues/7590 + +[go-1.23.6]: https://groups.google.com/g/golang-announce/c/xU1ZCHUZw3k + diff --git a/Makefile b/Makefile index 91c5682c..0fda6061 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ DIST_DIR = dist GOAMD64 = v1 GOPROXY = https://proxy.golang.org|direct GOTELEMETRY = off -GOTOOLCHAIN = go1.23.5 +GOTOOLCHAIN = go1.23.6 GPG_KEY = devteam@adguard.com GPG_KEY_PASSPHRASE = not-a-real-password NPM = npm diff --git a/bamboo-specs/release.yaml b/bamboo-specs/release.yaml index 32267cc7..70b5fc21 100644 --- a/bamboo-specs/release.yaml +++ b/bamboo-specs/release.yaml @@ -7,8 +7,8 @@ # Make sure to sync any changes with the branch overrides below. 'variables': 'channel': 'edge' - 'dockerFrontend': 'adguard/home-js-builder:2.0-bullseye' - 'dockerGo': 'adguard/go-builder:1.23.5--1' + 'dockerFrontend': 'adguard/home-js-builder:2.1-bullseye' + 'dockerGo': 'adguard/go-builder:1.23.6--1' 'stages': - 'Build frontend': @@ -277,8 +277,8 @@ # need to build a few of these. 'variables': 'channel': 'beta' - 'dockerFrontend': 'adguard/home-js-builder:2.0-bullseye' - 'dockerGo': 'adguard/go-builder:1.23.5--1' + 'dockerFrontend': 'adguard/home-js-builder:2.1-bullseye' + 'dockerGo': 'adguard/go-builder:1.23.6--1' # release-vX.Y.Z branches are the branches from which the actual final # release is built. - '^release-v[0-9]+\.[0-9]+\.[0-9]+': @@ -293,5 +293,5 @@ # are the ones that actually get released. 'variables': 'channel': 'release' - 'dockerFrontend': 'adguard/home-js-builder:2.0-bullseye' - 'dockerGo': 'adguard/go-builder:1.23.5--1' + 'dockerFrontend': 'adguard/home-js-builder:2.1-bullseye' + 'dockerGo': 'adguard/go-builder:1.23.6--1' diff --git a/bamboo-specs/test.yaml b/bamboo-specs/test.yaml index cd825541..2aaedf36 100644 --- a/bamboo-specs/test.yaml +++ b/bamboo-specs/test.yaml @@ -5,8 +5,8 @@ 'key': 'AHBRTSPECS' 'name': 'AdGuard Home - Build and run tests' 'variables': - 'dockerFrontend': 'adguard/home-js-builder:2.0-bullseye' - 'dockerGo': 'adguard/go-builder:1.23.5--1' + 'dockerFrontend': 'adguard/home-js-builder:2.1-bullseye' + 'dockerGo': 'adguard/go-builder:1.23.6--1' 'channel': 'development' 'stages': @@ -199,7 +199,7 @@ mv /tmp/AdGuardHome/AdGuardHome ./AdGuardHome - make VERBOSE=1 js-test-e2e + make VERBOSE=1 js-deps js-test-e2e 'requirements': - 'adg-docker': 'true' @@ -233,6 +233,6 @@ # Set the default release channel on the release branch to beta, as we # may need to build a few of these. 'variables': - 'dockerFrontend': 'adguard/home-js-builder:2.0-bullseye' - 'dockerGo': 'adguard/go-builder:1.23.5--1' + 'dockerFrontend': 'adguard/home-js-builder:2.1-bullseye' + 'dockerGo': 'adguard/go-builder:1.23.6--1' 'channel': 'candidate' diff --git a/client/package-lock.json b/client/package-lock.json index e76f521d..43835caf 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -52,7 +52,7 @@ "@babel/plugin-transform-runtime": "^7.24.3", "@babel/preset-env": "^7.24.5", "@babel/preset-react": "^7.24.1", - "@playwright/test": "^1.49.1", + "@playwright/test": "1.50.1", "@types/lodash": "^4.17.4", "@types/node": "^22.10.2", "@types/react": "^17.0.80", @@ -3195,13 +3195,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", - "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz", + "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.49.1" + "playwright": "1.50.1" }, "bin": { "playwright": "cli.js" @@ -12575,13 +12575,13 @@ } }, "node_modules/playwright": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", - "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz", + "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.49.1" + "playwright-core": "1.50.1" }, "bin": { "playwright": "cli.js" @@ -12594,9 +12594,9 @@ } }, "node_modules/playwright-core": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", - "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", + "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -20103,12 +20103,12 @@ "dev": true }, "@playwright/test": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", - "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz", + "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", "dev": true, "requires": { - "playwright": "1.49.1" + "playwright": "1.50.1" } }, "@rollup/rollup-android-arm-eabi": { @@ -27071,13 +27071,13 @@ } }, "playwright": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", - "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz", + "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", "dev": true, "requires": { "fsevents": "2.3.2", - "playwright-core": "1.49.1" + "playwright-core": "1.50.1" }, "dependencies": { "fsevents": { @@ -27090,9 +27090,9 @@ } }, "playwright-core": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", - "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", + "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", "dev": true }, "popper.js": { diff --git a/client/package.json b/client/package.json index 06bb2824..0673c21f 100644 --- a/client/package.json +++ b/client/package.json @@ -65,7 +65,7 @@ "@babel/plugin-transform-runtime": "^7.24.3", "@babel/preset-env": "^7.24.5", "@babel/preset-react": "^7.24.1", - "@playwright/test": "^1.49.1", + "@playwright/test": "1.50.1", "@types/lodash": "^4.17.4", "@types/node": "^22.10.2", "@types/react": "^17.0.80", diff --git a/client/src/components/Dashboard/UpstreamAvgTime.tsx b/client/src/components/Dashboard/UpstreamAvgTime.tsx index 48ed9e6a..8f5b4cab 100644 --- a/client/src/components/Dashboard/UpstreamAvgTime.tsx +++ b/client/src/components/Dashboard/UpstreamAvgTime.tsx @@ -10,6 +10,7 @@ import Card from '../ui/Card'; import DomainCell from './DomainCell'; import { DASHBOARD_TABLES_DEFAULT_PAGE_SIZE, TABLES_MIN_ROWS } from '../../helpers/constants'; +import { formatNumber } from '../../helpers/helpers'; interface TimeCellProps { value?: string | number; @@ -20,7 +21,7 @@ const TimeCell = ({ value }: TimeCellProps) => { return '–'; } - const valueInMilliseconds = round(Number(value) * 1000); + const valueInMilliseconds = formatNumber(round(Number(value) * 1000)); return (
diff --git a/client/src/components/Settings/Encryption/Form.tsx b/client/src/components/Settings/Encryption/Form.tsx index 7968cc3e..be03433d 100644 --- a/client/src/components/Settings/Encryption/Form.tsx +++ b/client/src/components/Settings/Encryption/Form.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef } from 'react'; +import React from 'react'; import { Trans, useTranslation } from 'react-i18next'; @@ -92,19 +92,7 @@ export type EncryptionFormValues = { type Props = { initialValues: EncryptionFormValues; - processingConfig: boolean; - processingValidate: boolean; - status_key?: string; - not_after?: string; - warning_validation?: string; - valid_chain?: boolean; - valid_key?: boolean; - valid_cert?: boolean; - valid_pair?: boolean; - dns_names?: string[]; - key_type?: string; - issuer?: string; - subject?: string; + encryption: EncryptionData; onSubmit: (values: EncryptionFormValues) => void; debouncedConfigValidation: (values: EncryptionFormValues) => void; setTlsConfig: (values: Partial) => void; @@ -130,24 +118,28 @@ const defaultValues = { export const Form = ({ initialValues, - processingConfig, - processingValidate, - not_after, - valid_chain, - valid_key, - valid_cert, - valid_pair, - dns_names, - key_type, - issuer, - subject, - warning_validation, + encryption, onSubmit, setTlsConfig, + debouncedConfigValidation, validateTlsConfig, }: Props) => { const { t } = useTranslation(); - const previousValuesRef = useRef(initialValues); + + const { + not_after, + valid_chain, + valid_key, + valid_cert, + valid_pair, + dns_names, + key_type, + issuer, + subject, + warning_validation, + processingConfig, + processingValidate, + } = encryption; const { control, @@ -166,8 +158,6 @@ export const Form = ({ mode: 'onBlur', }); - const watchedValues = watch(); - const { enabled: isEnabled, serve_plain_dns: servePlainDns, @@ -178,16 +168,11 @@ export const Form = ({ private_key_saved: privateKeySaved, certificate_path: certificatePath, certificate_source: certificateSource, - } = watchedValues; + } = watch(); - useEffect(() => { - const previousValues = previousValuesRef.current; - - if (JSON.stringify(previousValues) !== JSON.stringify(watchedValues)) { - // TODO(ik) onChange TLS config validation - previousValuesRef.current = watchedValues; - } - }, [watchedValues]); + const handleBlur = () => { + debouncedConfigValidation(getValues()); + }; const isSavingDisabled = () => { const processing = isSubmitting || processingConfig || processingValidate; @@ -243,7 +228,9 @@ export const Form = ({ } + render={({ field }) => ( + + )} />
@@ -288,6 +275,7 @@ export const Form = ({ placeholder={t('encryption_server_enter')} error={fieldState.error?.message} disabled={!isEnabled} + onBlur={handleBlur} /> )} /> @@ -337,6 +325,7 @@ export const Form = ({ const { value } = e.target; field.onChange(toNumber(value)); }} + onBlur={handleBlur} /> )} /> @@ -368,6 +357,7 @@ export const Form = ({ const { value } = e.target; field.onChange(toNumber(value)); }} + onBlur={handleBlur} /> )} /> @@ -399,6 +389,7 @@ export const Form = ({ const { value } = e.target; field.onChange(toNumber(value)); }} + onBlur={handleBlur} /> )} /> @@ -457,6 +448,7 @@ export const Form = ({ placeholder={t('encryption_certificates_input')} disabled={!isEnabled} error={fieldState.error?.message} + onBlur={handleBlur} /> )} /> @@ -471,6 +463,7 @@ export const Form = ({ placeholder={t('encryption_certificate_path')} error={fieldState.error?.message} disabled={!isEnabled} + onBlur={handleBlur} /> )} /> @@ -527,6 +520,7 @@ export const Form = ({ } field.onChange(checked); }} + onBlur={handleBlur} /> )} /> @@ -540,6 +534,7 @@ export const Form = ({ placeholder={t('encryption_key_input')} disabled={!isEnabled || privateKeySaved} error={fieldState.error?.message} + onBlur={handleBlur} /> )} /> @@ -555,6 +550,7 @@ export const Form = ({ placeholder={t('encryption_private_key_path')} error={fieldState.error?.message} disabled={!isEnabled} + onBlur={handleBlur} /> )} /> diff --git a/client/src/components/Settings/Encryption/index.tsx b/client/src/components/Settings/Encryption/index.tsx index 67c99842..a8c5dcda 100644 --- a/client/src/components/Settings/Encryption/index.tsx +++ b/client/src/components/Settings/Encryption/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { debounce } from 'lodash'; import { DEBOUNCE_TIMEOUT, ENCRYPTION_SOURCE } from '../../../helpers/constants'; @@ -18,19 +18,37 @@ type Props = { export const Encryption = ({ encryption, setTlsConfig, validateTlsConfig }: Props) => { const { t } = useTranslation(); - useEffect(() => { - if (encryption.enabled) { - validateTlsConfig(encryption); - } - }, [encryption, validateTlsConfig]); - const initialValues = useMemo((): EncryptionFormValues => { - const { certificate_chain, private_key, private_key_saved } = encryption; + const { + enabled, + serve_plain_dns, + server_name, + force_https, + port_https, + port_dns_over_tls, + port_dns_over_quic, + certificate_chain, + private_key, + certificate_path, + private_key_path, + private_key_saved, + } = encryption; const certificate_source = certificate_chain ? ENCRYPTION_SOURCE.CONTENT : ENCRYPTION_SOURCE.PATH; const key_source = private_key || private_key_saved ? ENCRYPTION_SOURCE.CONTENT : ENCRYPTION_SOURCE.PATH; return { - ...encryption, + enabled, + serve_plain_dns, + server_name, + force_https, + port_https, + port_dns_over_tls, + port_dns_over_quic, + certificate_chain, + private_key, + certificate_path, + private_key_path, + private_key_saved, certificate_source, key_source, }; @@ -75,7 +93,7 @@ export const Encryption = ({ encryption, setTlsConfig, validateTlsConfig }: Prop } }, []); - const debouncedConfigValidation = useCallback(debounce(validateConfig, DEBOUNCE_TIMEOUT), [validateConfig]); + const debouncedConfigValidation = useMemo(() => debounce(validateConfig, DEBOUNCE_TIMEOUT), [validateConfig]); return (
@@ -94,7 +112,7 @@ export const Encryption = ({ encryption, setTlsConfig, validateTlsConfig }: Prop debouncedConfigValidation={debouncedConfigValidation} setTlsConfig={setTlsConfig} validateTlsConfig={validateTlsConfig} - {...encryption} + encryption={encryption} /> )} diff --git a/client/src/components/ui/Controls/Checkbox/index.tsx b/client/src/components/ui/Controls/Checkbox/index.tsx index 32a97fba..09ed43fa 100644 --- a/client/src/components/ui/Controls/Checkbox/index.tsx +++ b/client/src/components/ui/Controls/Checkbox/index.tsx @@ -12,10 +12,14 @@ type Props = { className?: string; error?: string; onChange: (value: boolean) => void; + onBlur?: () => void; }; export const Checkbox = forwardRef( - ({ title, subtitle, value, name, disabled, error, className = 'checkbox--form', onChange, ...rest }, ref) => ( + ( + { title, subtitle, value, name, disabled, error, className = 'checkbox--form', onChange, onBlur, ...rest }, + ref, + ) => ( <>