From 5dff9b4adf14ba9b1a53967c6e239ea215398c5a Mon Sep 17 00:00:00 2001 From: "github-action[bot]" Date: Sun, 21 Dec 2025 19:39:15 +0100 Subject: [PATCH] Update On Sun Dec 21 19:39:14 CET 2025 --- .github/update.log | 1 + clash-meta-android/build.gradle.kts | 4 +- .../golang/clash/.github/patch/go1.25.patch | 188 +- .../golang/clash/.github/patch/go1.26.patch | 842 +++++ .../golang/clash/.github/workflows/build.yml | 4 + .../golang/clash/.github/workflows/test.yml | 9 +- .../src/foss/golang/clash/adapter/adapter.go | 14 +- .../golang/clash/adapter/inbound/https.go | 3 +- .../foss/golang/clash/adapter/inbound/util.go | 3 +- .../golang/clash/adapter/outbound/anytls.go | 14 +- .../golang/clash/adapter/outbound/base.go | 98 +- .../golang/clash/adapter/outbound/direct.go | 3 +- .../foss/golang/clash/adapter/outbound/dns.go | 3 +- .../golang/clash/adapter/outbound/http.go | 34 +- .../golang/clash/adapter/outbound/hysteria.go | 23 +- .../clash/adapter/outbound/hysteria2.go | 21 +- .../golang/clash/adapter/outbound/mieru.go | 24 +- .../golang/clash/adapter/outbound/reject.go | 1 + .../clash/adapter/outbound/shadowsocks.go | 48 +- .../clash/adapter/outbound/shadowsocksr.go | 44 +- .../golang/clash/adapter/outbound/singmux.go | 9 +- .../golang/clash/adapter/outbound/snell.go | 47 +- .../golang/clash/adapter/outbound/socks5.go | 43 +- .../foss/golang/clash/adapter/outbound/ssh.go | 20 +- .../golang/clash/adapter/outbound/sudoku.go | 225 +- .../golang/clash/adapter/outbound/trojan.go | 52 +- .../golang/clash/adapter/outbound/tuic.go | 48 +- .../golang/clash/adapter/outbound/vless.go | 51 +- .../golang/clash/adapter/outbound/vmess.go | 51 +- .../clash/adapter/outbound/wireguard.go | 17 +- .../clash/adapter/outboundgroup/fallback.go | 8 + .../adapter/outboundgroup/loadbalance.go | 12 + .../adapter/outboundgroup/patch_android.go | 64 - .../clash/adapter/outboundgroup/relay.go | 163 - .../clash/adapter/outboundgroup/selector.go | 8 + .../clash/adapter/outboundgroup/urltest.go | 8 + .../clash/adapter/outboundgroup/util.go | 24 + .../src/foss/golang/clash/adapter/parser.go | 73 +- .../golang/clash/adapter/provider/parser.go | 2 +- .../golang/clash/adapter/provider/provider.go | 18 +- .../foss/golang/clash/common/convert/util.go | 2 +- .../foss/golang/clash/common/net/websocket.go | 12 + .../clash/common/structure/structure.go | 4 + .../clash/common/structure/structure_test.go | 24 + .../clash/component/{tls => ca}/auth.go | 16 +- .../foss/golang/clash/component/ca/config.go | 11 +- .../foss/golang/clash/component/ca/keypair.go | 79 +- .../foss/golang/clash/component/ech/ech.go | 22 +- .../component/ech/echparser/echparser.go | 147 + .../foss/golang/clash/component/ech/key.go | 60 +- .../golang/clash/component/ech/key_test.go | 30 + .../golang/clash/component/generator/cmd.go | 11 +- .../golang/clash/component/geodata/init.go | 3 +- .../foss/golang/clash/component/http/http.go | 3 +- .../process/process_freebsd_amd64.go | 4 + .../clash/component/proxydialer/byname.go | 37 + .../component/proxydialer/proxydialer.go | 32 +- .../clash/component/proxydialer/sing.go | 67 +- .../clash/component/resource/vehicle.go | 3 +- .../golang/clash/component/tls/httpserver.go | 11 +- .../golang/clash/component/tls/reality.go | 14 +- .../foss/golang/clash/component/tls/utls.go | 56 +- .../clash/component/updater/update_core.go | 3 +- .../golang/clash/component/updater/utils.go | 3 +- .../src/foss/golang/clash/config/config.go | 18 +- .../foss/golang/clash/constant/adapters.go | 39 +- .../src/foss/golang/clash/constant/dns.go | 15 +- .../core/src/foss/golang/clash/dns/client.go | 2 +- .../core/src/foss/golang/clash/dns/doh.go | 20 +- .../core/src/foss/golang/clash/dns/doq.go | 5 +- .../src/foss/golang/clash/dns/resolver.go | 4 +- .../core/src/foss/golang/clash/dns/util.go | 79 +- .../src/foss/golang/clash/docker/file-name.sh | 4 +- .../src/foss/golang/clash/docs/config.yaml | 10 +- .../core/src/foss/golang/clash/go.mod | 26 +- .../core/src/foss/golang/clash/go.sum | 60 +- .../src/foss/golang/clash/hub/route/cache.go | 7 +- .../src/foss/golang/clash/hub/route/common.go | 162 +- .../foss/golang/clash/hub/route/configs.go | 6 +- .../golang/clash/hub/route/connections.go | 12 +- .../src/foss/golang/clash/hub/route/dns.go | 6 +- .../src/foss/golang/clash/hub/route/doh.go | 4 +- .../foss/golang/clash/hub/route/external.go | 2 +- .../src/foss/golang/clash/hub/route/groups.go | 14 +- .../foss/golang/clash/hub/route/provider.go | 6 +- .../foss/golang/clash/hub/route/proxies.go | 6 +- .../foss/golang/clash/hub/route/restart.go | 6 +- .../src/foss/golang/clash/hub/route/rules.go | 7 +- .../src/foss/golang/clash/hub/route/server.go | 61 +- .../foss/golang/clash/hub/route/upgrade.go | 6 +- .../golang/clash/listener/anytls/server.go | 28 +- .../golang/clash/listener/config/sudoku.go | 29 +- .../foss/golang/clash/listener/http/client.go | 3 +- .../foss/golang/clash/listener/http/hack.go | 5 +- .../foss/golang/clash/listener/http/proxy.go | 3 +- .../foss/golang/clash/listener/http/server.go | 31 +- .../golang/clash/listener/http/upgrade.go | 5 +- .../foss/golang/clash/listener/http/utils.go | 3 +- .../clash/listener/inbound/common_test.go | 30 +- .../golang/clash/listener/inbound/sudoku.go | 56 +- .../clash/listener/inbound/sudoku_test.go | 87 +- .../foss/golang/clash/listener/mixed/mixed.go | 31 +- .../clash/listener/sing_hysteria2/server.go | 33 +- .../golang/clash/listener/sing_tun/dns.go | 8 +- .../golang/clash/listener/sing_tun/prepare.go | 20 +- .../golang/clash/listener/sing_tun/server.go | 12 +- .../clash/listener/sing_vless/server.go | 36 +- .../clash/listener/sing_vmess/server.go | 36 +- .../foss/golang/clash/listener/socks/tcp.go | 31 +- .../golang/clash/listener/sudoku/server.go | 117 +- .../golang/clash/listener/trojan/server.go | 36 +- .../foss/golang/clash/listener/tuic/server.go | 26 +- .../src/foss/golang/clash/ntp/ntp/service.go | 7 +- .../clash/transport/gost-plugin/websocket.go | 7 +- .../foss/golang/clash/transport/gun/gun.go | 78 +- .../foss/golang/clash/transport/gun/server.go | 9 +- .../golang/clash/transport/gun/transport.go | 6 +- .../clash/transport/gun/transport_close.go | 23 +- .../hysteria/conns/faketcp/tcp_test.go | 192 -- .../clash/transport/hysteria/core/client.go | 6 +- .../transport/hysteria/transport/client.go | 4 +- .../clash/transport/shadowtls/shadowtls.go | 3 +- .../clash/transport/simple-obfs/http.go | 2 +- .../transport/sing-shadowtls/shadowtls.go | 2 +- .../golang/clash/transport/sudoku/address.go | 91 + .../clash/transport/sudoku/features_test.go | 192 ++ .../clash/transport/sudoku/handshake.go | 371 +++ .../clash/transport/sudoku/handshake_test.go | 249 ++ .../transport/sudoku/httpmask_strategy.go | 179 ++ .../clash/transport/sudoku/obfs_writer.go | 113 + .../clash/transport/sudoku/table_probe.go | 152 + .../golang/clash/transport/sudoku/tables.go | 30 + .../foss/golang/clash/transport/sudoku/uot.go | 158 + .../clash/transport/tuic/common/type.go | 7 +- .../clash/transport/tuic/pool_client.go | 154 +- .../golang/clash/transport/tuic/server.go | 4 +- .../foss/golang/clash/transport/tuic/tuic.go | 9 +- .../golang/clash/transport/tuic/v4/client.go | 38 +- .../golang/clash/transport/tuic/v5/client.go | 38 +- .../clash/transport/v2ray-plugin/websocket.go | 5 +- .../transport/vless/encryption/client.go | 17 +- .../transport/vless/encryption/client_test.go | 6 +- .../clash/transport/vless/encryption/key.go | 2 +- .../transport/vless/encryption/server.go | 2 +- .../clash/transport/vless/vision/vision.go | 16 + .../foss/golang/clash/transport/vmess/h2.go | 17 +- .../foss/golang/clash/transport/vmess/http.go | 2 +- .../foss/golang/clash/transport/vmess/tls.go | 30 +- .../golang/clash/transport/vmess/websocket.go | 33 +- .../golang/clash/tunnel/statistic/manager.go | 4 + .../clash/tunnel/statistic/patch_android.go | 7 - .../golang/clash/tunnel/statistic/tracker.go | 3 + .../core/src/foss/golang/go.mod | 26 +- .../core/src/foss/golang/go.sum | 60 +- .../core/src/main/golang/go.mod | 27 +- .../core/src/main/golang/go.sum | 61 +- clash-meta/transport/gun/gun.go | 13 +- clash-meta/transport/gun/server.go | 2 +- clash-nyanpasu/backend/Cargo.lock | 6 +- .../backend/tauri/src/utils/resolve.rs | 2 +- clash-nyanpasu/frontend/nyanpasu/package.json | 12 +- .../src/components/app/app-container.tsx | 2 +- .../src/components/ui/scroll-area.tsx | 154 +- .../pages/(experimental)/_modules/header.tsx | 2 +- .../experimental/settings/route.tsx | 7 +- .../src/pages/(experimental)/route.tsx | 6 +- clash-nyanpasu/frontend/ui/package.json | 4 +- clash-nyanpasu/manifest/version.json | 4 +- clash-nyanpasu/pnpm-lock.yaml | 367 +-- filebrowser/frontend/package.json | 2 +- filebrowser/frontend/pnpm-lock.yaml | 935 ++++-- filebrowser/frontend/src/i18n/hr.json | 20 +- filebrowser/frontend/src/i18n/ru.json | 32 +- filebrowser/go.mod | 2 +- filebrowser/go.sum | 4 +- geoip/config.json | 5 +- mihomo/transport/gun/gun.go | 13 +- mihomo/transport/gun/server.go | 2 +- .../luci-app-partexp/Makefile | 10 +- .../luci-app-partexp/README.md | 127 - .../luci-static/resources/view/partexp.js | 963 ++++++ .../luasrc/controller/partexp.lua | 50 - .../luasrc/model/cbi/partexp/global.lua | 79 - .../luci-app-partexp/luasrc/view/partexp.htm | 130 - .../luasrc/view/partexplog.htm | 16 - .../luasrc/view/partexplogrun.htm | 54 - .../luci-app-partexp/po/templates/partexp.po | 199 ++ .../luci-app-partexp/po/zh-cn/partexp.po | 96 - .../luci-app-partexp/po/zh_Hans/partexp.po | 192 +- .../luci-app-partexp/root/etc/config/partexp | 10 +- .../luci-app-partexp/root/etc/init.d/partexp | 751 ----- .../root/etc/partexp/lucilogpos | 1 - .../root/etc/partexp/partexp.log | 1 - .../root/etc/uci-defaults/40_luci-partexp | 5 - .../luci-app-partexp/root/usr/bin/partexp | 809 +++++ .../root/usr/libexec/rpcd/partexp | 228 ++ .../share/luci/menu.d/luci-app-partexp.json | 14 + .../share/rpcd/acl.d/luci-app-partexp.json | 28 +- sing-box/adapter/dns.go | 2 - .../cmd/internal/update_certificates/main.go | 95 + sing-box/common/certificate/chrome.go | 2817 +++++++++++++++++ sing-box/common/certificate/mozilla.go | 1071 ++++--- sing-box/common/certificate/store.go | 2 + sing-box/common/tls/acme.go | 12 +- sing-box/constant/certificate.go | 1 + sing-box/dns/client.go | 62 - sing-box/dns/router.go | 174 +- .../docs/configuration/certificate/index.md | 13 +- .../configuration/certificate/index.zh.md | 15 +- .../configuration/shared/dns01_challenge.md | 33 +- .../shared/dns01_challenge.zh.md | 33 +- sing-box/go.mod | 62 +- sing-box/go.sum | 157 +- sing-box/option/tls_acme.go | 4 +- sing-box/protocol/naive/quic/inbound_init.go | 10 +- small/gn/Makefile | 6 +- small/gn/src/out/last_commit_position.h | 4 +- .../model/cbi/shadowsocksr/client-config.lua | 3 + .../luasrc/view/shadowsocksr/ssrurl.htm | 11 +- .../root/usr/share/shadowsocksr/subscribe.lua | 20 +- small/v2ray-geodata/Makefile | 6 +- .../Views/SubSettingWindow.axaml | 8 + .../Views/SubSettingWindow.axaml.cs | 5 + v2rayn/v2rayN/v2rayN/App.xaml | 2 +- .../v2rayN/v2rayN/Views/SubSettingWindow.xaml | 20 + .../v2rayN/Views/SubSettingWindow.xaml.cs | 5 + yt-dlp/test/test_utils.py | 4 + yt-dlp/yt_dlp/utils/_utils.py | 6 +- 228 files changed, 11822 insertions(+), 4873 deletions(-) create mode 100644 clash-meta-android/core/src/foss/golang/clash/.github/patch/go1.26.patch delete mode 100644 clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/patch_android.go delete mode 100644 clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/relay.go rename clash-meta-android/core/src/foss/golang/clash/component/{tls => ca}/auth.go (64%) create mode 100644 clash-meta-android/core/src/foss/golang/clash/component/ech/echparser/echparser.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/component/ech/key_test.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/component/proxydialer/byname.go delete mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/hysteria/conns/faketcp/tcp_test.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/address.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/features_test.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake_test.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_strategy.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs_writer.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/table_probe.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/tables.go create mode 100644 clash-meta-android/core/src/foss/golang/clash/transport/sudoku/uot.go delete mode 100644 clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/patch_android.go delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/README.md create mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/htdocs/luci-static/resources/view/partexp.js delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/controller/partexp.lua delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/model/cbi/partexp/global.lua delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexp.htm delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexplog.htm delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexplogrun.htm create mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/po/templates/partexp.po delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/po/zh-cn/partexp.po delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/init.d/partexp delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/partexp/lucilogpos delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/partexp/partexp.log delete mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/uci-defaults/40_luci-partexp create mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/bin/partexp create mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/libexec/rpcd/partexp create mode 100644 openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/share/luci/menu.d/luci-app-partexp.json create mode 100644 sing-box/common/certificate/chrome.go diff --git a/.github/update.log b/.github/update.log index 152d46b0ae..1d2679c241 100644 --- a/.github/update.log +++ b/.github/update.log @@ -1218,3 +1218,4 @@ Update On Wed Dec 17 19:43:54 CET 2025 Update On Thu Dec 18 19:42:36 CET 2025 Update On Fri Dec 19 19:41:31 CET 2025 Update On Sat Dec 20 19:35:51 CET 2025 +Update On Sun Dec 21 19:39:06 CET 2025 diff --git a/clash-meta-android/build.gradle.kts b/clash-meta-android/build.gradle.kts index d6d2e0dbf1..a4e5ea009d 100644 --- a/clash-meta-android/build.gradle.kts +++ b/clash-meta-android/build.gradle.kts @@ -58,8 +58,8 @@ subprojects { minSdk = 21 targetSdk = 35 - versionName = "2.11.20" - versionCode = 211020 + versionName = "2.11.21" + versionCode = 211021 resValue("string", "release_name", "v$versionName") resValue("integer", "release_code", "$versionCode") diff --git a/clash-meta-android/core/src/foss/golang/clash/.github/patch/go1.25.patch b/clash-meta-android/core/src/foss/golang/clash/.github/patch/go1.25.patch index 626779dbdd..a7f724ff46 100644 --- a/clash-meta-android/core/src/foss/golang/clash/.github/patch/go1.25.patch +++ b/clash-meta-android/core/src/foss/golang/clash/.github/patch/go1.25.patch @@ -1,4 +1,5 @@ -Subject: [PATCH] Revert "runtime: always use LoadLibraryEx to load system libraries" +Subject: [PATCH] Fix os.RemoveAll not working on Windows7 +Revert "runtime: always use LoadLibraryEx to load system libraries" Revert "syscall: remove Windows 7 console handle workaround" Revert "net: remove sysSocket fallback for Windows 7" Revert "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng" @@ -655,3 +656,188 @@ diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go } else { h, e = loadlibrary(namep) } +Index: src/os/removeall_at.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go +--- a/src/os/removeall_at.go (revision f56f1e23507e646c85243a71bde7b9629b2f970c) ++++ b/src/os/removeall_at.go (revision 0a52622d2331ff975fb0442617ec19bc352bb2ed) +@@ -2,7 +2,7 @@ + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. + +-//go:build unix || wasip1 || windows ++//go:build unix || wasip1 + + package os + +@@ -175,3 +175,25 @@ + } + return newDirFile(fd, name) + } ++ ++func rootRemoveAll(r *Root, name string) error { ++ // Consistency with os.RemoveAll: Strip trailing /s from the name, ++ // so RemoveAll("not_a_directory/") succeeds. ++ for len(name) > 0 && IsPathSeparator(name[len(name)-1]) { ++ name = name[:len(name)-1] ++ } ++ if endsWithDot(name) { ++ // Consistency with os.RemoveAll: Return EINVAL when trying to remove . ++ return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL} ++ } ++ _, err := doInRoot(r, name, nil, func(parent sysfdType, name string) (struct{}, error) { ++ return struct{}{}, removeAllFrom(parent, name) ++ }) ++ if IsNotExist(err) { ++ return nil ++ } ++ if err != nil { ++ return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)} ++ } ++ return err ++} +Index: src/os/removeall_noat.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/removeall_noat.go b/src/os/removeall_noat.go +--- a/src/os/removeall_noat.go (revision f56f1e23507e646c85243a71bde7b9629b2f970c) ++++ b/src/os/removeall_noat.go (revision 0a52622d2331ff975fb0442617ec19bc352bb2ed) +@@ -2,7 +2,7 @@ + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. + +-//go:build (js && wasm) || plan9 ++//go:build (js && wasm) || plan9 || windows + + package os + +@@ -140,3 +140,22 @@ + } + return err + } ++ ++func rootRemoveAll(r *Root, name string) error { ++ if endsWithDot(name) { ++ // Consistency with os.RemoveAll: Return EINVAL when trying to remove . ++ return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL} ++ } ++ if err := checkPathEscapesLstat(r, name); err != nil { ++ if err == syscall.ENOTDIR { ++ // Some intermediate path component is not a directory. ++ // RemoveAll treats this as success (since the target doesn't exist). ++ return nil ++ } ++ return &PathError{Op: "RemoveAll", Path: name, Err: err} ++ } ++ if err := RemoveAll(joinPath(r.root.name, name)); err != nil { ++ return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)} ++ } ++ return nil ++} +Index: src/os/root_noopenat.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/root_noopenat.go b/src/os/root_noopenat.go +--- a/src/os/root_noopenat.go (revision f56f1e23507e646c85243a71bde7b9629b2f970c) ++++ b/src/os/root_noopenat.go (revision 0a52622d2331ff975fb0442617ec19bc352bb2ed) +@@ -11,7 +11,6 @@ + "internal/filepathlite" + "internal/stringslite" + "sync/atomic" +- "syscall" + "time" + ) + +@@ -185,25 +184,6 @@ + } + return nil + } +- +-func rootRemoveAll(r *Root, name string) error { +- if endsWithDot(name) { +- // Consistency with os.RemoveAll: Return EINVAL when trying to remove . +- return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL} +- } +- if err := checkPathEscapesLstat(r, name); err != nil { +- if err == syscall.ENOTDIR { +- // Some intermediate path component is not a directory. +- // RemoveAll treats this as success (since the target doesn't exist). +- return nil +- } +- return &PathError{Op: "RemoveAll", Path: name, Err: err} +- } +- if err := RemoveAll(joinPath(r.root.name, name)); err != nil { +- return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)} +- } +- return nil +-} + + func rootReadlink(r *Root, name string) (string, error) { + if err := checkPathEscapesLstat(r, name); err != nil { +Index: src/os/root_openat.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/root_openat.go b/src/os/root_openat.go +--- a/src/os/root_openat.go (revision f56f1e23507e646c85243a71bde7b9629b2f970c) ++++ b/src/os/root_openat.go (revision 0a52622d2331ff975fb0442617ec19bc352bb2ed) +@@ -194,28 +194,6 @@ + return nil + } + +-func rootRemoveAll(r *Root, name string) error { +- // Consistency with os.RemoveAll: Strip trailing /s from the name, +- // so RemoveAll("not_a_directory/") succeeds. +- for len(name) > 0 && IsPathSeparator(name[len(name)-1]) { +- name = name[:len(name)-1] +- } +- if endsWithDot(name) { +- // Consistency with os.RemoveAll: Return EINVAL when trying to remove . +- return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL} +- } +- _, err := doInRoot(r, name, nil, func(parent sysfdType, name string) (struct{}, error) { +- return struct{}{}, removeAllFrom(parent, name) +- }) +- if IsNotExist(err) { +- return nil +- } +- if err != nil { +- return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)} +- } +- return err +-} +- + func rootRename(r *Root, oldname, newname string) error { + _, err := doInRoot(r, oldname, nil, func(oldparent sysfdType, oldname string) (struct{}, error) { + _, err := doInRoot(r, newname, nil, func(newparent sysfdType, newname string) (struct{}, error) { +Index: src/os/root_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/root_windows.go b/src/os/root_windows.go +--- a/src/os/root_windows.go (revision f56f1e23507e646c85243a71bde7b9629b2f970c) ++++ b/src/os/root_windows.go (revision 0a52622d2331ff975fb0442617ec19bc352bb2ed) +@@ -402,3 +402,14 @@ + } + return fi.Mode(), nil + } ++ ++func checkPathEscapes(r *Root, name string) error { ++ if !filepathlite.IsLocal(name) { ++ return errPathEscapes ++ } ++ return nil ++} ++ ++func checkPathEscapesLstat(r *Root, name string) error { ++ return checkPathEscapes(r, name) ++} diff --git a/clash-meta-android/core/src/foss/golang/clash/.github/patch/go1.26.patch b/clash-meta-android/core/src/foss/golang/clash/.github/patch/go1.26.patch new file mode 100644 index 0000000000..29dab4d0a6 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/.github/patch/go1.26.patch @@ -0,0 +1,842 @@ +Subject: [PATCH] Fix os.RemoveAll not working on Windows7 +Revert "runtime: always use LoadLibraryEx to load system libraries" +Revert "syscall: remove Windows 7 console handle workaround" +Revert "net: remove sysSocket fallback for Windows 7" +Revert "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng" +--- +Index: src/crypto/internal/sysrand/rand_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/crypto/internal/sysrand/rand_windows.go b/src/crypto/internal/sysrand/rand_windows.go +--- a/src/crypto/internal/sysrand/rand_windows.go (revision c599a8f2385849a225d02843b3c6389dbfc5aa69) ++++ b/src/crypto/internal/sysrand/rand_windows.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) +@@ -7,5 +7,26 @@ + import "internal/syscall/windows" + + func read(b []byte) error { +- return windows.ProcessPrng(b) ++ // RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at ++ // most 1<<31-1 bytes at a time so that this works the same on 32-bit ++ // and 64-bit systems. ++ return batched(windows.RtlGenRandom, 1<<31-1)(b) ++} ++ ++// batched returns a function that calls f to populate a []byte by chunking it ++// into subslices of, at most, readMax bytes. ++func batched(f func([]byte) error, readMax int) func([]byte) error { ++ return func(out []byte) error { ++ for len(out) > 0 { ++ read := len(out) ++ if read > readMax { ++ read = readMax ++ } ++ if err := f(out[:read]); err != nil { ++ return err ++ } ++ out = out[read:] ++ } ++ return nil ++ } + } +Index: src/crypto/rand/rand.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go +--- a/src/crypto/rand/rand.go (revision c599a8f2385849a225d02843b3c6389dbfc5aa69) ++++ b/src/crypto/rand/rand.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) +@@ -25,7 +25,7 @@ + // - On legacy Linux (< 3.17), Reader opens /dev/urandom on first use. + // - On macOS, iOS, and OpenBSD Reader, uses arc4random_buf(3). + // - On NetBSD, Reader uses the kern.arandom sysctl. +-// - On Windows, Reader uses the ProcessPrng API. ++// - On Windows systems, Reader uses the RtlGenRandom API. + // - On js/wasm, Reader uses the Web Crypto API. + // - On wasip1/wasm, Reader uses random_get. + // +Index: src/internal/syscall/windows/syscall_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go +--- a/src/internal/syscall/windows/syscall_windows.go (revision c599a8f2385849a225d02843b3c6389dbfc5aa69) ++++ b/src/internal/syscall/windows/syscall_windows.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) +@@ -421,7 +421,7 @@ + //sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock + //sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW + +-//sys ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng ++//sys RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036 + + type FILE_ID_BOTH_DIR_INFO struct { + NextEntryOffset uint32 +Index: src/internal/syscall/windows/zsyscall_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go +--- a/src/internal/syscall/windows/zsyscall_windows.go (revision c599a8f2385849a225d02843b3c6389dbfc5aa69) ++++ b/src/internal/syscall/windows/zsyscall_windows.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) +@@ -38,7 +38,6 @@ + + var ( + modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) +- modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll")) + modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) + modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) + modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) +@@ -63,7 +62,7 @@ + procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") + procRevertToSelf = modadvapi32.NewProc("RevertToSelf") + procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") +- procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng") ++ procSystemFunction036 = modadvapi32.NewProc("SystemFunction036") + procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") + procCreateEventW = modkernel32.NewProc("CreateEventW") + procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort") +@@ -244,12 +243,12 @@ + return + } + +-func ProcessPrng(buf []byte) (err error) { ++func RtlGenRandom(buf []byte) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } +- r1, _, e1 := syscall.SyscallN(procProcessPrng.Addr(), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf))) ++ r1, _, e1 := syscall.SyscallN(procSystemFunction036.Addr(), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) + if r1 == 0 { + err = errnoErr(e1) + } +Index: src/runtime/os_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go +--- a/src/runtime/os_windows.go (revision c599a8f2385849a225d02843b3c6389dbfc5aa69) ++++ b/src/runtime/os_windows.go (revision ea2726a6fa25fbfa1092e696e522eafca544d24c) +@@ -40,7 +40,8 @@ + //go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll" + //go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll" + //go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll" +-//go:cgo_import_dynamic runtime._LoadLibraryExW LoadLibraryExW%3 "kernel32.dll" ++//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" ++//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll" + //go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll" + //go:cgo_import_dynamic runtime._QueryPerformanceCounter QueryPerformanceCounter%1 "kernel32.dll" + //go:cgo_import_dynamic runtime._QueryPerformanceFrequency QueryPerformanceFrequency%1 "kernel32.dll" +@@ -74,7 +75,6 @@ + // Following syscalls are available on every Windows PC. + // All these variables are set by the Windows executable + // loader before the Go program starts. +- _AddVectoredContinueHandler, + _AddVectoredExceptionHandler, + _CloseHandle, + _CreateEventA, +@@ -97,7 +97,8 @@ + _GetSystemInfo, + _GetThreadContext, + _SetThreadContext, +- _LoadLibraryExW, ++ _LoadLibraryW, ++ _LoadLibraryA, + _PostQueuedCompletionStatus, + _QueryPerformanceCounter, + _QueryPerformanceFrequency, +@@ -126,8 +127,23 @@ + _WriteFile, + _ stdFunction + +- // Use ProcessPrng to generate cryptographically random data. +- _ProcessPrng stdFunction ++ // Following syscalls are only available on some Windows PCs. ++ // We will load syscalls, if available, before using them. ++ _AddDllDirectory, ++ _AddVectoredContinueHandler, ++ _LoadLibraryExA, ++ _LoadLibraryExW, ++ _ stdFunction ++ ++ // Use RtlGenRandom to generate cryptographically random data. ++ // This approach has been recommended by Microsoft (see issue ++ // 15589 for details). ++ // The RtlGenRandom is not listed in advapi32.dll, instead ++ // RtlGenRandom function can be found by searching for SystemFunction036. ++ // Also some versions of Mingw cannot link to SystemFunction036 ++ // when building executable as Cgo. So load SystemFunction036 ++ // manually during runtime startup. ++ _RtlGenRandom stdFunction + + // Load ntdll.dll manually during startup, otherwise Mingw + // links wrong printf function to cgo executable (see issue +@@ -144,13 +160,6 @@ + _ stdFunction + ) + +-var ( +- bcryptprimitivesdll = [...]uint16{'b', 'c', 'r', 'y', 'p', 't', 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 's', '.', 'd', 'l', 'l', 0} +- ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} +- powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} +- winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} +-) +- + // Function to be called by windows CreateThread + // to start new os thread. + func tstart_stdcall(newm *m) +@@ -242,9 +251,40 @@ + return unsafe.String(&sysDirectory[0], sysDirectoryLen) + } + +-func windowsLoadSystemLib(name []uint16) uintptr { +- const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 +- return stdcall(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) ++//go:linkname syscall_getSystemDirectory syscall.getSystemDirectory ++func syscall_getSystemDirectory() string { ++ return unsafe.String(&sysDirectory[0], sysDirectoryLen) ++} ++ ++func windowsLoadSystemLib(name []byte) uintptr { ++ if useLoadLibraryEx { ++ return stdcall(_LoadLibraryExA, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) ++ } else { ++ absName := append(sysDirectory[:sysDirectoryLen], name...) ++ return stdcall(_LoadLibraryA, uintptr(unsafe.Pointer(&absName[0]))) ++ } ++} ++ ++const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 ++ ++// When available, this function will use LoadLibraryEx with the filename ++// parameter and the important SEARCH_SYSTEM32 argument. But on systems that ++// do not have that option, absoluteFilepath should contain a fallback ++// to the full path inside of system32 for use with vanilla LoadLibrary. ++// ++//go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary ++func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) { ++ if useLoadLibraryEx { ++ handle, _, err = syscall_syscalln(uintptr(unsafe.Pointer(_LoadLibraryExW)), 3, uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) ++ } else { ++ handle, _, err = syscall_syscalln(uintptr(unsafe.Pointer(_LoadLibraryW)), 1, uintptr(unsafe.Pointer(absoluteFilepath))) ++ } ++ KeepAlive(filename) ++ KeepAlive(absoluteFilepath) ++ if handle != 0 { ++ err = 0 ++ } ++ return + } + + //go:linkname windows_QueryPerformanceCounter internal/syscall/windows.QueryPerformanceCounter +@@ -262,13 +302,28 @@ + } + + func loadOptionalSyscalls() { +- bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:]) +- if bcryptPrimitives == 0 { +- throw("bcryptprimitives.dll not found") ++ var kernel32dll = []byte("kernel32.dll\000") ++ k32 := stdcall(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0]))) ++ if k32 == 0 { ++ throw("kernel32.dll not found") + } +- _ProcessPrng = windowsFindfunc(bcryptPrimitives, []byte("ProcessPrng\000")) ++ _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000")) ++ _AddVectoredContinueHandler = windowsFindfunc(k32, []byte("AddVectoredContinueHandler\000")) ++ _LoadLibraryExA = windowsFindfunc(k32, []byte("LoadLibraryExA\000")) ++ _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000")) ++ useLoadLibraryEx = (_LoadLibraryExW != nil && _LoadLibraryExA != nil && _AddDllDirectory != nil) ++ ++ initSysDirectory() + +- n32 := windowsLoadSystemLib(ntdlldll[:]) ++ var advapi32dll = []byte("advapi32.dll\000") ++ a32 := windowsLoadSystemLib(advapi32dll) ++ if a32 == 0 { ++ throw("advapi32.dll not found") ++ } ++ _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000")) ++ ++ var ntdll = []byte("ntdll.dll\000") ++ n32 := windowsLoadSystemLib(ntdll) + if n32 == 0 { + throw("ntdll.dll not found") + } +@@ -297,7 +352,7 @@ + context uintptr + } + +- powrprof := windowsLoadSystemLib(powrprofdll[:]) ++ powrprof := windowsLoadSystemLib([]byte("powrprof.dll\000")) + if powrprof == 0 { + return // Running on Windows 7, where we don't need it anyway. + } +@@ -351,6 +406,22 @@ + // in sys_windows_386.s and sys_windows_amd64.s: + func getlasterror() uint32 + ++// When loading DLLs, we prefer to use LoadLibraryEx with ++// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not ++// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_* ++// flags are not available on some versions of Windows without a ++// security patch. ++// ++// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says: ++// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows ++// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on ++// systems that have KB2533623 installed. To determine whether the ++// flags are available, use GetProcAddress to get the address of the ++// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories ++// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_* ++// flags can be used with LoadLibraryEx." ++var useLoadLibraryEx bool ++ + var timeBeginPeriodRetValue uint32 + + // osRelaxMinNS indicates that sysmon shouldn't osRelax if the next +@@ -417,7 +488,8 @@ + // Only load winmm.dll if we need it. + // This avoids a dependency on winmm.dll for Go programs + // that run on new Windows versions. +- m32 := windowsLoadSystemLib(winmmdll[:]) ++ var winmmdll = []byte("winmm.dll\000") ++ m32 := windowsLoadSystemLib(winmmdll) + if m32 == 0 { + print("runtime: LoadLibraryExW failed; errno=", getlasterror(), "\n") + throw("winmm.dll not found") +@@ -458,6 +530,28 @@ + canUseLongPaths = true + } + ++var osVersionInfo struct { ++ majorVersion uint32 ++ minorVersion uint32 ++ buildNumber uint32 ++} ++ ++func initOsVersionInfo() { ++ info := windows.OSVERSIONINFOW{} ++ info.OSVersionInfoSize = uint32(unsafe.Sizeof(info)) ++ stdcall(_RtlGetVersion, uintptr(unsafe.Pointer(&info))) ++ osVersionInfo.majorVersion = info.MajorVersion ++ osVersionInfo.minorVersion = info.MinorVersion ++ osVersionInfo.buildNumber = info.BuildNumber ++} ++ ++//go:linkname rtlGetNtVersionNumbers syscall.rtlGetNtVersionNumbers ++func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) { ++ *majorVersion = osVersionInfo.majorVersion ++ *minorVersion = osVersionInfo.minorVersion ++ *buildNumber = osVersionInfo.buildNumber ++} ++ + func osinit() { + asmstdcallAddr = unsafe.Pointer(windows.AsmStdCallAddr()) + +@@ -470,8 +564,8 @@ + initHighResTimer() + timeBeginPeriodRetValue = osRelax(false) + +- initSysDirectory() + initLongPathSupport() ++ initOsVersionInfo() + + numCPUStartup = getCPUCount() + +@@ -487,7 +581,7 @@ + //go:nosplit + func readRandom(r []byte) int { + n := 0 +- if stdcall(_ProcessPrng, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { ++ if stdcall(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { + n = len(r) + } + return n +Index: src/net/hook_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go +--- a/src/net/hook_windows.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) ++++ b/src/net/hook_windows.go (revision 44e76f7cf1bc6e04b5da724e0b2e48f393713506) +@@ -13,6 +13,7 @@ + hostsFilePath = windows.GetSystemDirectory() + "/Drivers/etc/hosts" + + // Placeholders for socket system calls. ++ socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket + wsaSocketFunc func(int32, int32, int32, *syscall.WSAProtocolInfo, uint32, uint32) (syscall.Handle, error) = windows.WSASocket + connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect + listenFunc func(syscall.Handle, int) error = syscall.Listen +Index: src/net/internal/socktest/main_test.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go +--- a/src/net/internal/socktest/main_test.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) ++++ b/src/net/internal/socktest/main_test.go (revision 44e76f7cf1bc6e04b5da724e0b2e48f393713506) +@@ -2,7 +2,7 @@ + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. + +-//go:build !js && !plan9 && !wasip1 && !windows ++//go:build !js && !plan9 && !wasip1 + + package socktest_test + +Index: src/net/internal/socktest/main_windows_test.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/net/internal/socktest/main_windows_test.go b/src/net/internal/socktest/main_windows_test.go +new file mode 100644 +--- /dev/null (revision 44e76f7cf1bc6e04b5da724e0b2e48f393713506) ++++ b/src/net/internal/socktest/main_windows_test.go (revision 44e76f7cf1bc6e04b5da724e0b2e48f393713506) +@@ -0,0 +1,22 @@ ++// Copyright 2015 The Go Authors. All rights reserved. ++// Use of this source code is governed by a BSD-style ++// license that can be found in the LICENSE file. ++ ++package socktest_test ++ ++import "syscall" ++ ++var ( ++ socketFunc func(int, int, int) (syscall.Handle, error) ++ closeFunc func(syscall.Handle) error ++) ++ ++func installTestHooks() { ++ socketFunc = sw.Socket ++ closeFunc = sw.Closesocket ++} ++ ++func uninstallTestHooks() { ++ socketFunc = syscall.Socket ++ closeFunc = syscall.Closesocket ++} +Index: src/net/internal/socktest/sys_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go +--- a/src/net/internal/socktest/sys_windows.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) ++++ b/src/net/internal/socktest/sys_windows.go (revision 44e76f7cf1bc6e04b5da724e0b2e48f393713506) +@@ -9,6 +9,38 @@ + "syscall" + ) + ++// Socket wraps [syscall.Socket]. ++func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) { ++ sw.once.Do(sw.init) ++ ++ so := &Status{Cookie: cookie(family, sotype, proto)} ++ sw.fmu.RLock() ++ f, _ := sw.fltab[FilterSocket] ++ sw.fmu.RUnlock() ++ ++ af, err := f.apply(so) ++ if err != nil { ++ return syscall.InvalidHandle, err ++ } ++ s, so.Err = syscall.Socket(family, sotype, proto) ++ if err = af.apply(so); err != nil { ++ if so.Err == nil { ++ syscall.Closesocket(s) ++ } ++ return syscall.InvalidHandle, err ++ } ++ ++ sw.smu.Lock() ++ defer sw.smu.Unlock() ++ if so.Err != nil { ++ sw.stats.getLocked(so.Cookie).OpenFailed++ ++ return syscall.InvalidHandle, so.Err ++ } ++ nso := sw.addLocked(s, family, sotype, proto) ++ sw.stats.getLocked(nso.Cookie).Opened++ ++ return s, nil ++} ++ + // WSASocket wraps [syscall.WSASocket]. + func (sw *Switch) WSASocket(family, sotype, proto int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (s syscall.Handle, err error) { + sw.once.Do(sw.init) +Index: src/net/main_windows_test.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go +--- a/src/net/main_windows_test.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) ++++ b/src/net/main_windows_test.go (revision 44e76f7cf1bc6e04b5da724e0b2e48f393713506) +@@ -12,6 +12,7 @@ + + var ( + // Placeholders for saving original socket system calls. ++ origSocket = socketFunc + origWSASocket = wsaSocketFunc + origClosesocket = poll.CloseFunc + origConnect = connectFunc +@@ -21,6 +22,7 @@ + ) + + func installTestHooks() { ++ socketFunc = sw.Socket + wsaSocketFunc = sw.WSASocket + poll.CloseFunc = sw.Closesocket + connectFunc = sw.Connect +@@ -30,6 +32,7 @@ + } + + func uninstallTestHooks() { ++ socketFunc = origSocket + wsaSocketFunc = origWSASocket + poll.CloseFunc = origClosesocket + connectFunc = origConnect +Index: src/net/sock_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go +--- a/src/net/sock_windows.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) ++++ b/src/net/sock_windows.go (revision 44e76f7cf1bc6e04b5da724e0b2e48f393713506) +@@ -20,6 +20,21 @@ + func sysSocket(family, sotype, proto int) (syscall.Handle, error) { + s, err := wsaSocketFunc(int32(family), int32(sotype), int32(proto), + nil, 0, windows.WSA_FLAG_OVERLAPPED|windows.WSA_FLAG_NO_HANDLE_INHERIT) ++ if err == nil { ++ return s, nil ++ } ++ // WSA_FLAG_NO_HANDLE_INHERIT flag is not supported on some ++ // old versions of Windows, see ++ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx ++ // for details. Just use syscall.Socket, if windows.WSASocket failed. ++ ++ // See ../syscall/exec_unix.go for description of ForkLock. ++ syscall.ForkLock.RLock() ++ s, err = socketFunc(family, sotype, proto) ++ if err == nil { ++ syscall.CloseOnExec(s) ++ } ++ syscall.ForkLock.RUnlock() + if err != nil { + return syscall.InvalidHandle, os.NewSyscallError("socket", err) + } +Index: src/syscall/exec_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go +--- a/src/syscall/exec_windows.go (revision b0d48afabb9fd14976c27221cb525c5d2ebbfe79) ++++ b/src/syscall/exec_windows.go (revision b4aece36e51ecce81c3ee9fe03e31db552e90018) +@@ -15,7 +15,6 @@ + "unsafe" + ) + +-// ForkLock is not used on Windows. + var ForkLock sync.RWMutex + + // EscapeArg rewrites command line argument s as prescribed +@@ -304,6 +303,9 @@ + var zeroProcAttr ProcAttr + var zeroSysProcAttr SysProcAttr + ++//go:linkname rtlGetNtVersionNumbers ++func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) ++ + func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { + if len(argv0) == 0 { + return 0, 0, EWINDOWS +@@ -367,6 +369,17 @@ + } + } + ++ var maj, min, build uint32 ++ rtlGetNtVersionNumbers(&maj, &min, &build) ++ isWin7 := maj < 6 || (maj == 6 && min <= 1) ++ // NT kernel handles are divisible by 4, with the bottom 3 bits left as ++ // a tag. The fully set tag correlates with the types of handles we're ++ // concerned about here. Except, the kernel will interpret some ++ // special handle values, like -1, -2, and so forth, so kernelbase.dll ++ // checks to see that those bottom three bits are checked, but that top ++ // bit is not checked. ++ isLegacyWin7ConsoleHandle := func(handle Handle) bool { return isWin7 && handle&0x10000003 == 3 } ++ + p, _ := GetCurrentProcess() + parentProcess := p + if sys.ParentProcess != 0 { +@@ -375,7 +388,15 @@ + fd := make([]Handle, len(attr.Files)) + for i := range attr.Files { + if attr.Files[i] > 0 { +- err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) ++ destinationProcessHandle := parentProcess ++ ++ // On Windows 7, console handles aren't real handles, and can only be duplicated ++ // into the current process, not a parent one, which amounts to the same thing. ++ if parentProcess != p && isLegacyWin7ConsoleHandle(Handle(attr.Files[i])) { ++ destinationProcessHandle = p ++ } ++ ++ err := DuplicateHandle(p, Handle(attr.Files[i]), destinationProcessHandle, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) + if err != nil { + return 0, 0, err + } +@@ -406,6 +427,14 @@ + + fd = append(fd, sys.AdditionalInheritedHandles...) + ++ // On Windows 7, console handles aren't real handles, so don't pass them ++ // through to PROC_THREAD_ATTRIBUTE_HANDLE_LIST. ++ for i := range fd { ++ if isLegacyWin7ConsoleHandle(fd[i]) { ++ fd[i] = 0 ++ } ++ } ++ + // The presence of a NULL handle in the list is enough to cause PROC_THREAD_ATTRIBUTE_HANDLE_LIST + // to treat the entire list as empty, so remove NULL handles. + j := 0 +Index: src/syscall/dll_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go +--- a/src/syscall/dll_windows.go (revision b4aece36e51ecce81c3ee9fe03e31db552e90018) ++++ b/src/syscall/dll_windows.go (revision ea2726a6fa25fbfa1092e696e522eafca544d24c) +@@ -119,14 +119,7 @@ + } + + //go:linkname loadsystemlibrary +-func loadsystemlibrary(filename *uint16) (uintptr, Errno) { +- const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 +- handle, _, err := SyscallN(uintptr(__LoadLibraryExW), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) +- if handle != 0 { +- err = 0 +- } +- return handle, err +-} ++func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno) + + //go:linkname getprocaddress + func getprocaddress(handle uintptr, procname *uint8) (uintptr, Errno) { +@@ -143,6 +136,9 @@ + Handle Handle + } + ++//go:linkname getSystemDirectory ++func getSystemDirectory() string // Implemented in runtime package. ++ + // LoadDLL loads the named DLL file into memory. + // + // If name is not an absolute path and is not a known system DLL used by +@@ -159,7 +155,11 @@ + var h uintptr + var e Errno + if sysdll.IsSystemDLL[name] { +- h, e = loadsystemlibrary(namep) ++ absoluteFilepathp, err := UTF16PtrFromString(getSystemDirectory() + name) ++ if err != nil { ++ return nil, err ++ } ++ h, e = loadsystemlibrary(namep, absoluteFilepathp) + } else { + h, e = loadlibrary(namep) + } +Index: src/os/removeall_at.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go +--- a/src/os/removeall_at.go (revision ea2726a6fa25fbfa1092e696e522eafca544d24c) ++++ b/src/os/removeall_at.go (revision d47e0d22130d597dcf9daa6b41fd9501274f0cb2) +@@ -2,7 +2,7 @@ + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. + +-//go:build unix || wasip1 || windows ++//go:build unix || wasip1 + + package os + +@@ -175,3 +175,25 @@ + } + return newDirFile(fd, name) + } ++ ++func rootRemoveAll(r *Root, name string) error { ++ // Consistency with os.RemoveAll: Strip trailing /s from the name, ++ // so RemoveAll("not_a_directory/") succeeds. ++ for len(name) > 0 && IsPathSeparator(name[len(name)-1]) { ++ name = name[:len(name)-1] ++ } ++ if endsWithDot(name) { ++ // Consistency with os.RemoveAll: Return EINVAL when trying to remove . ++ return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL} ++ } ++ _, err := doInRoot(r, name, nil, func(parent sysfdType, name string) (struct{}, error) { ++ return struct{}{}, removeAllFrom(parent, name) ++ }) ++ if IsNotExist(err) { ++ return nil ++ } ++ if err != nil { ++ return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)} ++ } ++ return err ++} +Index: src/os/removeall_noat.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/removeall_noat.go b/src/os/removeall_noat.go +--- a/src/os/removeall_noat.go (revision ea2726a6fa25fbfa1092e696e522eafca544d24c) ++++ b/src/os/removeall_noat.go (revision d47e0d22130d597dcf9daa6b41fd9501274f0cb2) +@@ -2,7 +2,7 @@ + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. + +-//go:build (js && wasm) || plan9 ++//go:build (js && wasm) || plan9 || windows + + package os + +@@ -140,3 +140,22 @@ + } + return err + } ++ ++func rootRemoveAll(r *Root, name string) error { ++ if endsWithDot(name) { ++ // Consistency with os.RemoveAll: Return EINVAL when trying to remove . ++ return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL} ++ } ++ if err := checkPathEscapesLstat(r, name); err != nil { ++ if err == syscall.ENOTDIR { ++ // Some intermediate path component is not a directory. ++ // RemoveAll treats this as success (since the target doesn't exist). ++ return nil ++ } ++ return &PathError{Op: "RemoveAll", Path: name, Err: err} ++ } ++ if err := RemoveAll(joinPath(r.root.name, name)); err != nil { ++ return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)} ++ } ++ return nil ++} +Index: src/os/root_noopenat.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/root_noopenat.go b/src/os/root_noopenat.go +--- a/src/os/root_noopenat.go (revision ea2726a6fa25fbfa1092e696e522eafca544d24c) ++++ b/src/os/root_noopenat.go (revision d47e0d22130d597dcf9daa6b41fd9501274f0cb2) +@@ -11,7 +11,6 @@ + "internal/filepathlite" + "internal/stringslite" + "sync/atomic" +- "syscall" + "time" + ) + +@@ -185,25 +184,6 @@ + } + return nil + } +- +-func rootRemoveAll(r *Root, name string) error { +- if endsWithDot(name) { +- // Consistency with os.RemoveAll: Return EINVAL when trying to remove . +- return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL} +- } +- if err := checkPathEscapesLstat(r, name); err != nil { +- if err == syscall.ENOTDIR { +- // Some intermediate path component is not a directory. +- // RemoveAll treats this as success (since the target doesn't exist). +- return nil +- } +- return &PathError{Op: "RemoveAll", Path: name, Err: err} +- } +- if err := RemoveAll(joinPath(r.root.name, name)); err != nil { +- return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)} +- } +- return nil +-} + + func rootReadlink(r *Root, name string) (string, error) { + if err := checkPathEscapesLstat(r, name); err != nil { +Index: src/os/root_openat.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/root_openat.go b/src/os/root_openat.go +--- a/src/os/root_openat.go (revision ea2726a6fa25fbfa1092e696e522eafca544d24c) ++++ b/src/os/root_openat.go (revision d47e0d22130d597dcf9daa6b41fd9501274f0cb2) +@@ -196,28 +196,6 @@ + return nil + } + +-func rootRemoveAll(r *Root, name string) error { +- // Consistency with os.RemoveAll: Strip trailing /s from the name, +- // so RemoveAll("not_a_directory/") succeeds. +- for len(name) > 0 && IsPathSeparator(name[len(name)-1]) { +- name = name[:len(name)-1] +- } +- if endsWithDot(name) { +- // Consistency with os.RemoveAll: Return EINVAL when trying to remove . +- return &PathError{Op: "RemoveAll", Path: name, Err: syscall.EINVAL} +- } +- _, err := doInRoot(r, name, nil, func(parent sysfdType, name string) (struct{}, error) { +- return struct{}{}, removeAllFrom(parent, name) +- }) +- if IsNotExist(err) { +- return nil +- } +- if err != nil { +- return &PathError{Op: "RemoveAll", Path: name, Err: underlyingError(err)} +- } +- return err +-} +- + func rootRename(r *Root, oldname, newname string) error { + _, err := doInRoot(r, oldname, nil, func(oldparent sysfdType, oldname string) (struct{}, error) { + _, err := doInRoot(r, newname, nil, func(newparent sysfdType, newname string) (struct{}, error) { +Index: src/os/root_windows.go +IDEA additional info: +Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP +<+>UTF-8 +=================================================================== +diff --git a/src/os/root_windows.go b/src/os/root_windows.go +--- a/src/os/root_windows.go (revision ea2726a6fa25fbfa1092e696e522eafca544d24c) ++++ b/src/os/root_windows.go (revision d47e0d22130d597dcf9daa6b41fd9501274f0cb2) +@@ -402,3 +402,14 @@ + } + return fi.Mode(), nil + } ++ ++func checkPathEscapes(r *Root, name string) error { ++ if !filepathlite.IsLocal(name) { ++ return errPathEscapes ++ } ++ return nil ++} ++ ++func checkPathEscapesLstat(r *Root, name string) error { ++ return checkPathEscapes(r, name) ++} diff --git a/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml b/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml index 9ba36ed8ae..3fe99a6b62 100644 --- a/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml +++ b/clash-meta-android/core/src/foss/golang/clash/.github/workflows/build.yml @@ -59,6 +59,8 @@ jobs: - { goos: linux, goarch: s390x, output: s390x, debian: s390x, rpm: s390x } - { goos: linux, goarch: ppc64le, output: ppc64le, debian: ppc64el, rpm: ppc64le } + # Go 1.25 with special patch can work on Windows 7 + # https://github.com/MetaCubeX/go/commits/release-branch.go1.25/ - { goos: windows, goarch: '386', output: '386' } - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible } # old style file name will be removed in next released - { goos: windows, goarch: amd64, goamd64: v3, output: amd64 } @@ -176,6 +178,8 @@ jobs: # 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7" # 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround" # a17d959debdb04cd550016a3501dd09d50cd62e7: "runtime: always use LoadLibraryEx to load system libraries" + # sepical fix: + # - os.RemoveAll not working on Windows7 - name: Revert Golang1.25 commit for Windows7/8 if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '' }} run: | diff --git a/clash-meta-android/core/src/foss/golang/clash/.github/workflows/test.yml b/clash-meta-android/core/src/foss/golang/clash/.github/workflows/test.yml index ddddb5eee5..af3ae18fe7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/.github/workflows/test.yml +++ b/clash-meta-android/core/src/foss/golang/clash/.github/workflows/test.yml @@ -24,6 +24,7 @@ jobs: - 'ubuntu-24.04-arm' # arm64 linux - 'macos-15-intel' # amd64 macos go-version: + - '1.26.0-rc.1' - '1.25' - '1.24' - '1.23' @@ -49,11 +50,17 @@ jobs: go-version: ${{ matrix.go-version }} - name: Revert Golang commit for Windows7/8 - if: ${{ runner.os == 'Windows' && matrix.go-version != '1.20' }} + if: ${{ runner.os == 'Windows' && matrix.go-version != '1.20' && matrix.go-version != '1.26.0-rc.1' }} run: | cd $(go env GOROOT) patch --verbose -p 1 < $GITHUB_WORKSPACE/.github/patch/go${{matrix.go-version}}.patch + - name: Revert Golang commit for Windows7/8 + if: ${{ runner.os == 'Windows' && matrix.go-version == '1.26.0-rc.1' }} + run: | + cd $(go env GOROOT) + patch --verbose -p 1 < $GITHUB_WORKSPACE/.github/patch/go1.26.patch + - name: Remove inbound test for macOS if: ${{ runner.os == 'macOS' }} run: | diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/adapter.go b/clash-meta-android/core/src/foss/golang/clash/adapter/adapter.go index ef8d4ee347..6f20c08abb 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/adapter.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/adapter.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "net" - "net/http" "net/url" "strings" "time" @@ -17,6 +16,8 @@ import ( "github.com/metacubex/mihomo/component/ca" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" + + "github.com/metacubex/http" ) var UnifiedDelay = atomic.NewBool(false) @@ -153,8 +154,9 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { mapping["mptcp"] = proxyInfo.MPTCP mapping["smux"] = proxyInfo.SMUX mapping["interface"] = proxyInfo.Interface - mapping["dialer-proxy"] = proxyInfo.DialerProxy mapping["routing-mark"] = proxyInfo.RoutingMark + mapping["provider-name"] = proxyInfo.ProviderName + mapping["dialer-proxy"] = proxyInfo.DialerProxy return json.Marshal(mapping) } @@ -177,14 +179,12 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In p.history.Pop() } - state, ok := p.extra.Load(url) - if !ok { - state = &internalProxyState{ + state, _ := p.extra.LoadOrStoreFn(url, func() *internalProxyState { + return &internalProxyState{ history: queue.New[C.DelayHistory](defaultHistoriesNum), alive: atomic.NewBool(true), } - p.extra.Store(url, state) - } + }) if !satisfied { record.Delay = 0 diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/inbound/https.go b/clash-meta-android/core/src/foss/golang/clash/adapter/inbound/https.go index 24b30804b7..4ea468555f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/inbound/https.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/inbound/https.go @@ -2,9 +2,10 @@ package inbound import ( "net" - "net/http" C "github.com/metacubex/mihomo/constant" + + "github.com/metacubex/http" ) // NewHTTPS receive CONNECT request and return ConnContext diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/inbound/util.go b/clash-meta-android/core/src/foss/golang/clash/adapter/inbound/util.go index 17e6479cbb..0cc1e761a7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/inbound/util.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/inbound/util.go @@ -2,12 +2,13 @@ package inbound import ( "net" - "net/http" "net/netip" "strings" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/socks5" + + "github.com/metacubex/http" ) func parseSocksAddr(target socks5.Addr) *C.Metadata { diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/anytls.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/anytls.go index 78b1e40cb7..c17f27d55e 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/anytls.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/anytls.go @@ -6,8 +6,7 @@ import ( "strconv" "time" - CN "github.com/metacubex/mihomo/common/net" - "github.com/metacubex/mihomo/component/dialer" + N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/anytls" @@ -20,7 +19,6 @@ import ( type AnyTLS struct { *Base client *anytls.Client - dialer proxydialer.SingDialer option *AnyTLSOption } @@ -65,7 +63,7 @@ func (t *AnyTLS) ListenPacketContext(ctx context.Context, metadata *C.Metadata) // create uot on tcp destination := M.SocksaddrFromNet(metadata.UDPAddr()) - return newPacketConn(CN.NewThreadSafePacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination})), t), nil + return newPacketConn(N.NewThreadSafePacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination})), t), nil } // SupportUOT implements C.ProxyAdapter @@ -92,18 +90,18 @@ func NewAnyTLS(option AnyTLSOption) (*AnyTLS, error) { name: option.Name, addr: addr, tp: C.AnyTLS, + pdName: option.ProviderName, udp: option.UDP, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, } - - singDialer := proxydialer.NewByNameSingDialer(option.DialerProxy, dialer.NewDialer(outbound.DialOptions()...)) - outbound.dialer = singDialer + outbound.dialer = option.NewDialer(outbound.DialOptions()) + singDialer := proxydialer.NewSingDialer(outbound.dialer) tOption := anytls.ClientConfig{ Password: option.Password, diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/base.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/base.go index 93f6e14256..4a4c412d05 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/base.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/base.go @@ -12,6 +12,7 @@ import ( N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" "github.com/metacubex/mihomo/component/resolver" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" @@ -26,15 +27,17 @@ type ProxyAdapter interface { type Base struct { name string addr string - iface string tp C.AdapterType + pdName string udp bool xudp bool tfo bool mpTcp bool + iface string rmark int - id string prefer C.DNSPrefer + dialer C.Dialer + id string } // Name implements C.ProxyAdapter @@ -56,35 +59,15 @@ func (b *Base) Type() C.AdapterType { return b.tp } -// StreamConnContext implements C.ProxyAdapter -func (b *Base) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { - return c, C.ErrNotSupport -} - func (b *Base) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) { return nil, C.ErrNotSupport } -// DialContextWithDialer implements C.ProxyAdapter -func (b *Base) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - return nil, C.ErrNotSupport -} - // ListenPacketContext implements C.ProxyAdapter func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) { return nil, C.ErrNotSupport } -// ListenPacketWithDialer implements C.ProxyAdapter -func (b *Base) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - return nil, C.ErrNotSupport -} - -// SupportWithDialer implements C.ProxyAdapter -func (b *Base) SupportWithDialer() C.NetWork { - return C.InvalidNet -} - // SupportUOT implements C.ProxyAdapter func (b *Base) SupportUOT() bool { return false @@ -103,6 +86,7 @@ func (b *Base) ProxyInfo() (info C.ProxyInfo) { info.SMUX = false info.Interface = b.iface info.RoutingMark = b.rmark + info.ProviderName = b.pdName return } @@ -178,12 +162,30 @@ func (b *Base) Close() error { } type BasicOption struct { - TFO bool `proxy:"tfo,omitempty"` - MPTCP bool `proxy:"mptcp,omitempty"` - Interface string `proxy:"interface-name,omitempty"` - RoutingMark int `proxy:"routing-mark,omitempty"` - IPVersion string `proxy:"ip-version,omitempty"` - DialerProxy string `proxy:"dialer-proxy,omitempty"` // don't apply this option into groups, but can set a group name in a proxy + TFO bool `proxy:"tfo,omitempty"` + MPTCP bool `proxy:"mptcp,omitempty"` + Interface string `proxy:"interface-name,omitempty"` + RoutingMark int `proxy:"routing-mark,omitempty"` + IPVersion C.DNSPrefer `proxy:"ip-version,omitempty"` + DialerProxy string `proxy:"dialer-proxy,omitempty"` // don't apply this option into groups, but can set a group name in a proxy + + // + // The following parameters are used internally, assign value by the structure decoder are disallowed + // + DialerForAPI C.Dialer `proxy:"-"` // the dialer used for API usage has higher priority than all the above configurations. + ProviderName string `proxy:"-"` +} + +func (b *BasicOption) NewDialer(opts []dialer.Option) C.Dialer { + cDialer := b.DialerForAPI + if cDialer == nil { + if b.DialerProxy != "" { + cDialer = proxydialer.NewByName(b.DialerProxy) + } else { + cDialer = dialer.NewDialer(opts...) + } + } + return cDialer } type BaseOption struct { @@ -217,6 +219,7 @@ func NewBase(opt BaseOption) *Base { type conn struct { N.ExtendedConn chain C.Chain + pdChain C.Chain adapterAddr string } @@ -238,9 +241,15 @@ func (c *conn) Chains() C.Chain { return c.chain } +// ProviderChains implements C.Connection +func (c *conn) ProviderChains() C.Chain { + return c.pdChain +} + // AppendToChains implements C.Connection func (c *conn) AppendToChains(a C.ProxyAdapter) { c.chain = append(c.chain, a.Name()) + c.pdChain = append(c.pdChain, a.ProxyInfo().ProviderName) } func (c *conn) Upstream() any { @@ -263,7 +272,7 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { if _, ok := c.(syscall.Conn); !ok { // exclusion system conn like *net.TCPConn c = N.NewDeadlineConn(c) // most conn from outbound can't handle readDeadline correctly } - cc := &conn{N.NewExtendedConn(c), nil, a.Addr()} + cc := &conn{N.NewExtendedConn(c), nil, nil, a.Addr()} cc.AppendToChains(a) return cc } @@ -271,6 +280,7 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { type packetConn struct { N.EnhancePacketConn chain C.Chain + pdChain C.Chain adapterName string connID string adapterAddr string @@ -291,9 +301,15 @@ func (c *packetConn) Chains() C.Chain { return c.chain } +// ProviderChains implements C.Connection +func (c *packetConn) ProviderChains() C.Chain { + return c.pdChain +} + // AppendToChains implements C.Connection func (c *packetConn) AppendToChains(a C.ProxyAdapter) { c.chain = append(c.chain, a.Name()) + c.pdChain = append(c.pdChain, a.ProxyInfo().ProviderName) } func (c *packetConn) LocalAddr() net.Addr { @@ -322,7 +338,7 @@ func newPacketConn(pc net.PacketConn, a ProxyAdapter) C.PacketConn { if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly } - cpc := &packetConn{epc, nil, a.Name(), utils.NewUUIDV4().String(), a.Addr(), a.ResolveUDP} + cpc := &packetConn{epc, nil, nil, a.Name(), utils.NewUUIDV4().String(), a.Addr(), a.ResolveUDP} cpc.AppendToChains(a) return cpc } @@ -348,17 +364,6 @@ func (p *autoCloseProxyAdapter) DialContext(ctx context.Context, metadata *C.Met return c, nil } -func (p *autoCloseProxyAdapter) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - c, err := p.ProxyAdapter.DialContextWithDialer(ctx, dialer, metadata) - if err != nil { - return nil, err - } - if c, ok := c.(AddRef); ok { - c.AddRef(p) - } - return c, nil -} - func (p *autoCloseProxyAdapter) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) { pc, err := p.ProxyAdapter.ListenPacketContext(ctx, metadata) if err != nil { @@ -370,17 +375,6 @@ func (p *autoCloseProxyAdapter) ListenPacketContext(ctx context.Context, metadat return pc, nil } -func (p *autoCloseProxyAdapter) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - pc, err := p.ProxyAdapter.ListenPacketWithDialer(ctx, dialer, metadata) - if err != nil { - return nil, err - } - if pc, ok := pc.(AddRef); ok { - pc.AddRef(p) - } - return pc, nil -} - func (p *autoCloseProxyAdapter) Close() error { p.closeOnce.Do(func() { log.Debugln("Closing outdated proxy [%s]", p.Name()) diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/direct.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/direct.go index be8367ba8f..42cd8def13 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/direct.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/direct.go @@ -69,12 +69,13 @@ func NewDirectWithOption(option DirectOption) *Direct { Base: &Base{ name: option.Name, tp: C.Direct, + pdName: option.ProviderName, udp: true, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, loopBack: loopback.NewDetector(), } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/dns.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/dns.go index 2522850247..5e253d2a01 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/dns.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/dns.go @@ -158,12 +158,13 @@ func NewDnsWithOption(option DnsOption) *Dns { Base: &Base{ name: option.Name, tp: C.Dns, + pdName: option.ProviderName, udp: true, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, } } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/http.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/http.go index 7b898e2eb6..7f282a21c9 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/http.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/http.go @@ -3,19 +3,18 @@ package outbound import ( "bufio" "context" - "crypto/tls" "encoding/base64" "errors" "fmt" "net" - "net/http" "strconv" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/ca" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" + + "github.com/metacubex/http" + "github.com/metacubex/tls" ) type Http struct { @@ -61,18 +60,7 @@ func (h *Http) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Me // DialContext implements C.ProxyAdapter func (h *Http) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) { - return h.DialContextWithDialer(ctx, dialer.NewDialer(h.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - if len(h.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(h.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } - c, err := dialer.DialContext(ctx, "tcp", h.addr) + c, err := h.dialer.DialContext(ctx, "tcp", h.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", h.addr, err) } @@ -89,11 +77,6 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad return NewConn(c, h), nil } -// SupportWithDialer implements C.ProxyAdapter -func (h *Http) SupportWithDialer() C.NetWork { - return C.TCP -} - // ProxyInfo implements C.ProxyAdapter func (h *Http) ProxyInfo() C.ProxyInfo { info := h.Base.ProxyInfo() @@ -183,20 +166,23 @@ func NewHttp(option HttpOption) (*Http, error) { } } - return &Http{ + outbound := &Http{ Base: &Base{ name: option.Name, addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.Http, + pdName: option.ProviderName, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, user: option.UserName, pass: option.Password, tlsConfig: tlsConfig, option: &option, - }, nil + } + outbound.dialer = option.NewDialer(outbound.DialOptions()) + return outbound, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/hysteria.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/hysteria.go index 9ba118f39b..94c0c2e02d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/hysteria.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/hysteria.go @@ -2,7 +2,6 @@ package outbound import ( "context" - "crypto/tls" "encoding/base64" "fmt" "net" @@ -13,8 +12,6 @@ import ( "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/ech" - "github.com/metacubex/mihomo/component/proxydialer" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" hyCongestion "github.com/metacubex/mihomo/transport/hysteria/congestion" @@ -24,6 +21,8 @@ import ( "github.com/metacubex/mihomo/transport/hysteria/transport" "github.com/metacubex/mihomo/transport/hysteria/utils" + "github.com/metacubex/tls" + "github.com/metacubex/quic-go" "github.com/metacubex/quic-go/congestion" M "github.com/metacubex/sing/common/metadata" @@ -46,7 +45,7 @@ type Hysteria struct { option *HysteriaOption client *core.Client - tlsConfig *tlsC.Config + tlsConfig *tls.Config echConfig *ech.Config } @@ -74,16 +73,8 @@ func (h *Hysteria) genHdc(ctx context.Context) utils.PacketDialer { return &hyDialerWithContext{ ctx: context.Background(), hyDialer: func(network string, rAddr net.Addr) (net.PacketConn, error) { - var err error - var cDialer C.Dialer = dialer.NewDialer(h.DialOptions()...) - if len(h.option.DialerProxy) > 0 { - cDialer, err = proxydialer.NewByName(h.option.DialerProxy, cDialer) - if err != nil { - return nil, err - } - } rAddrPort, _ := netip.ParseAddrPort(rAddr.String()) - return cDialer.ListenPacket(ctx, network, "", rAddrPort) + return h.dialer.ListenPacket(ctx, network, "", rAddrPort) }, remoteAddr: func(addr string) (net.Addr, error) { udpAddr, err := resolveUDPAddr(ctx, "udp", addr, h.prefer) @@ -184,7 +175,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) { if err != nil { return nil, err } - tlsClientConfig := tlsC.UConfig(tlsConfig) + tlsClientConfig := tlsConfig quicConfig := &quic.Config{ InitialStreamReceiveWindow: uint64(option.ReceiveWindowConn), @@ -252,17 +243,19 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) { name: option.Name, addr: addr, tp: C.Hysteria, + pdName: option.ProviderName, udp: true, tfo: option.FastOpen, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, client: client, tlsConfig: tlsClientConfig, echConfig: echConfig, } + outbound.dialer = option.NewDialer(outbound.DialOptions()) return outbound, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/hysteria2.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/hysteria2.go index bc203366f0..0e797a9845 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/hysteria2.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/hysteria2.go @@ -2,19 +2,16 @@ package outbound import ( "context" - "crypto/tls" "errors" "fmt" "net" "strconv" "time" - CN "github.com/metacubex/mihomo/common/net" + N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/ca" - "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/proxydialer" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" tuicCommon "github.com/metacubex/mihomo/transport/tuic/common" @@ -22,6 +19,7 @@ import ( "github.com/metacubex/quic-go" "github.com/metacubex/sing-quic/hysteria2" M "github.com/metacubex/sing/common/metadata" + "github.com/metacubex/tls" ) func init() { @@ -36,7 +34,6 @@ type Hysteria2 struct { option *Hysteria2Option client *hysteria2.Client - dialer proxydialer.SingDialer } type Hysteria2Option struct { @@ -87,7 +84,7 @@ func (h *Hysteria2) ListenPacketContext(ctx context.Context, metadata *C.Metadat if pc == nil { return nil, errors.New("packetConn is nil") } - return newPacketConn(CN.NewThreadSafePacketConn(pc), h), nil + return newPacketConn(N.NewThreadSafePacketConn(pc), h), nil } // Close implements C.ProxyAdapter @@ -112,16 +109,16 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { name: option.Name, addr: addr, tp: C.Hysteria2, + pdName: option.ProviderName, udp: true, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, } - - singDialer := proxydialer.NewByNameSingDialer(option.DialerProxy, dialer.NewDialer(outbound.DialOptions()...)) - outbound.dialer = singDialer + outbound.dialer = option.NewDialer(outbound.DialOptions()) + singDialer := proxydialer.NewSingDialer(outbound.dialer) var salamanderPassword string if len(option.Obfs) > 0 { @@ -159,7 +156,7 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { tlsConfig.NextProtos = option.ALPN } - tlsClientConfig := tlsC.UConfig(tlsConfig) + tlsClientConfig := tlsConfig echConfig, err := option.ECHOpts.Parse() if err != nil { return nil, err @@ -192,7 +189,7 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { CWND: option.CWND, UdpMTU: option.UdpMTU, ServerAddress: func(ctx context.Context) (*net.UDPAddr, error) { - udpAddr, err := resolveUDPAddr(ctx, "udp", addr, C.NewDNSPrefer(option.IPVersion)) + udpAddr, err := resolveUDPAddr(ctx, "udp", addr, option.IPVersion) if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/mieru.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/mieru.go index e09b1898f2..af790b6e05 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/mieru.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/mieru.go @@ -8,9 +8,7 @@ import ( "strconv" "sync" - CN "github.com/metacubex/mihomo/common/net" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/proxydialer" + N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/resolver" C "github.com/metacubex/mihomo/constant" @@ -106,7 +104,7 @@ func (m *Mieru) ListenPacketContext(ctx context.Context, metadata *C.Metadata) ( if err != nil { return nil, fmt.Errorf("dial to %s failed: %w", metadata.UDPAddr(), err) } - return newPacketConn(CN.NewThreadSafePacketConn(mierucommon.NewUDPAssociateWrapper(mierucommon.NewPacketOverStreamTunnel(c))), m), nil + return newPacketConn(N.NewThreadSafePacketConn(mierucommon.NewUDPAssociateWrapper(mierucommon.NewPacketOverStreamTunnel(c))), m), nil } // SupportUOT implements C.ProxyAdapter @@ -130,20 +128,12 @@ func (m *Mieru) ensureClientIsRunning() error { } // Create a dialer and add it to the client config, before starting the client. - var dialer C.Dialer = dialer.NewDialer(m.DialOptions()...) - var err error - if len(m.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(m.option.DialerProxy, dialer) - if err != nil { - return err - } - } config, err := m.client.Load() if err != nil { return err } - config.Dialer = dialer - config.PacketDialer = mieruPacketDialer{Dialer: dialer} + config.Dialer = m.dialer + config.PacketDialer = mieruPacketDialer{Dialer: m.dialer} config.Resolver = mieruDNSResolver{prefer: m.prefer} if err := m.client.Store(config); err != nil { return err @@ -177,16 +167,18 @@ func NewMieru(option MieruOption) (*Mieru, error) { Base: &Base{ name: option.Name, addr: addr, - iface: option.Interface, tp: C.Mieru, + pdName: option.ProviderName, udp: option.UDP, xudp: false, + iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, client: c, } + outbound.dialer = option.NewDialer(outbound.DialOptions()) return outbound, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/reject.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/reject.go index 9e0bb022ee..97bcdd5ad6 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/reject.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/reject.go @@ -17,6 +17,7 @@ type Reject struct { } type RejectOption struct { + BasicOption Name string `proxy:"name"` } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocks.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocks.go index c6cfa9147b..8e4d9354ad 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocks.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocks.go @@ -8,8 +8,6 @@ import ( N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/structure" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/ntp" gost "github.com/metacubex/mihomo/transport/gost-plugin" @@ -191,17 +189,6 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada // DialContext implements C.ProxyAdapter func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) { - return ss.DialContextWithDialer(ctx, dialer.NewDialer(ss.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - if len(ss.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } var c net.Conn if ss.kcptunClient != nil { c, err = ss.kcptunClient.OpenStream(ctx, func(ctx context.Context) (net.PacketConn, net.Addr, error) { @@ -213,7 +200,7 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale return nil, nil, err } - pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort()) + pc, err := ss.dialer.ListenPacket(ctx, "udp", "", addr.AddrPort()) if err != nil { return nil, nil, err } @@ -221,7 +208,7 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale return pc, addr, nil }) } else { - c, err = dialer.DialContext(ctx, "tcp", ss.addr) + c, err = ss.dialer.DialContext(ctx, "tcp", ss.addr) } if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) @@ -237,25 +224,14 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale // ListenPacketContext implements C.ProxyAdapter func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) { - return ss.ListenPacketWithDialer(ctx, dialer.NewDialer(ss.DialOptions()...), metadata) -} - -// ListenPacketWithDialer implements C.ProxyAdapter -func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { if ss.option.UDPOverTCP { - tcpConn, err := ss.DialContextWithDialer(ctx, dialer, metadata) + tcpConn, err := ss.DialContext(ctx, metadata) if err != nil { return nil, err } return ss.ListenPacketOnStreamConn(ctx, tcpConn, metadata) } - if len(ss.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } - if err = ss.ResolveUDP(ctx, metadata); err != nil { + if err := ss.ResolveUDP(ctx, metadata); err != nil { return nil, err } addr, err := resolveUDPAddr(ctx, "udp", ss.addr, ss.prefer) @@ -263,7 +239,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial return nil, err } - pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort()) + pc, err := ss.dialer.ListenPacket(ctx, "udp", "", addr.AddrPort()) if err != nil { return nil, err } @@ -271,11 +247,6 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial return newPacketConn(pc, ss), nil } -// SupportWithDialer implements C.ProxyAdapter -func (ss *ShadowSocks) SupportWithDialer() C.NetWork { - return C.ALLNet -} - // ProxyInfo implements C.ProxyAdapter func (ss *ShadowSocks) ProxyInfo() C.ProxyInfo { info := ss.Base.ProxyInfo() @@ -482,17 +453,18 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { return nil, fmt.Errorf("ss %s unknown udp over tcp protocol version: %d", addr, option.UDPOverTCPVersion) } - return &ShadowSocks{ + outbound := &ShadowSocks{ Base: &Base{ name: option.Name, addr: addr, tp: C.Shadowsocks, + pdName: option.ProviderName, udp: option.UDP, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, method: method, @@ -504,5 +476,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { shadowTLSOption: shadowTLSOpt, restlsConfig: restlsConfig, kcptunClient: kcptunClient, - }, nil + } + outbound.dialer = option.NewDialer(outbound.DialOptions()) + return outbound, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocksr.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocksr.go index efc368a4ad..09c3924e27 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocksr.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/shadowsocksr.go @@ -8,8 +8,6 @@ import ( "strconv" N "github.com/metacubex/mihomo/common/net" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/shadowsocks/core" "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" @@ -68,18 +66,7 @@ func (ssr *ShadowSocksR) StreamConnContext(ctx context.Context, c net.Conn, meta // DialContext implements C.ProxyAdapter func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) { - return ssr.DialContextWithDialer(ctx, dialer.NewDialer(ssr.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - if len(ssr.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(ssr.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } - c, err := dialer.DialContext(ctx, "tcp", ssr.addr) + c, err := ssr.dialer.DialContext(ctx, "tcp", ssr.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err) } @@ -94,18 +81,7 @@ func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dia // ListenPacketContext implements C.ProxyAdapter func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) { - return ssr.ListenPacketWithDialer(ctx, dialer.NewDialer(ssr.DialOptions()...), metadata) -} - -// ListenPacketWithDialer implements C.ProxyAdapter -func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - if len(ssr.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(ssr.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } - if err = ssr.ResolveUDP(ctx, metadata); err != nil { + if err := ssr.ResolveUDP(ctx, metadata); err != nil { return nil, err } addr, err := resolveUDPAddr(ctx, "udp", ssr.addr, ssr.prefer) @@ -113,7 +89,7 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di return nil, err } - pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort()) + pc, err := ssr.dialer.ListenPacket(ctx, "udp", "", addr.AddrPort()) if err != nil { return nil, err } @@ -123,11 +99,6 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di return newPacketConn(&ssrPacketConn{EnhancePacketConn: epc, rAddr: addr}, ssr), nil } -// SupportWithDialer implements C.ProxyAdapter -func (ssr *ShadowSocksR) SupportWithDialer() C.NetWork { - return C.ALLNet -} - // ProxyInfo implements C.ProxyAdapter func (ssr *ShadowSocksR) ProxyInfo() C.ProxyInfo { info := ssr.Base.ProxyInfo() @@ -186,23 +157,26 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { return nil, fmt.Errorf("ssr %s initialize protocol error: %w", addr, err) } - return &ShadowSocksR{ + outbound := &ShadowSocksR{ Base: &Base{ name: option.Name, addr: addr, tp: C.ShadowsocksR, + pdName: option.ProviderName, udp: option.UDP, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, cipher: coreCiph, obfs: obfs, protocol: protocol, - }, nil + } + outbound.dialer = option.NewDialer(outbound.DialOptions()) + return outbound, nil } type ssrPacketConn struct { diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/singmux.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/singmux.go index cd9ec90458..55bd6ac385 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/singmux.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/singmux.go @@ -3,8 +3,7 @@ package outbound import ( "context" - CN "github.com/metacubex/mihomo/common/net" - "github.com/metacubex/mihomo/component/dialer" + N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" @@ -17,7 +16,6 @@ import ( type SingMux struct { ProxyAdapter client *mux.Client - dialer proxydialer.SingDialer onlyTcp bool } @@ -61,7 +59,7 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata) if pc == nil { return nil, E.New("packetConn is nil") } - return newPacketConn(CN.NewThreadSafePacketConn(pc), s), nil + return newPacketConn(N.NewThreadSafePacketConn(pc), s), nil } func (s *SingMux) SupportUDP() bool { @@ -96,7 +94,7 @@ func NewSingMux(option SingMuxOption, proxy ProxyAdapter) (ProxyAdapter, error) // TODO // "TCP Brutal is only supported on Linux-based systems" - singDialer := proxydialer.NewSingDialer(proxy, dialer.NewDialer(proxy.DialOptions()...), option.Statistic) + singDialer := proxydialer.NewSingDialer(proxydialer.New(proxy, option.Statistic)) client, err := mux.NewClient(mux.Options{ Dialer: singDialer, Logger: log.SingLogger, @@ -117,7 +115,6 @@ func NewSingMux(option SingMuxOption, proxy ProxyAdapter) (ProxyAdapter, error) outbound := &SingMux{ ProxyAdapter: proxy, client: client, - dialer: singDialer, onlyTcp: option.OnlyTcp, } return outbound, nil diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/snell.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/snell.go index ef3603e628..64295a7083 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/snell.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/snell.go @@ -8,8 +8,6 @@ import ( N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/structure" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" obfs "github.com/metacubex/mihomo/transport/simple-obfs" "github.com/metacubex/mihomo/transport/snell" @@ -89,18 +87,7 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn return NewConn(c, s), err } - return s.DialContextWithDialer(ctx, dialer.NewDialer(s.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - if len(s.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(s.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } - c, err := dialer.DialContext(ctx, "tcp", s.addr) + c, err := s.dialer.DialContext(ctx, "tcp", s.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", s.addr, err) } @@ -115,22 +102,11 @@ func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta // ListenPacketContext implements C.ProxyAdapter func (s *Snell) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) { - return s.ListenPacketWithDialer(ctx, dialer.NewDialer(s.DialOptions()...), metadata) -} - -// ListenPacketWithDialer implements C.ProxyAdapter -func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (C.PacketConn, error) { var err error - if len(s.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(s.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } if err = s.ResolveUDP(ctx, metadata); err != nil { return nil, err } - c, err := dialer.DialContext(ctx, "tcp", s.addr) + c, err := s.dialer.DialContext(ctx, "tcp", s.addr) if err != nil { return nil, err } @@ -141,11 +117,6 @@ func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met return newPacketConn(pc, s), nil } -// SupportWithDialer implements C.ProxyAdapter -func (s *Snell) SupportWithDialer() C.NetWork { - return C.ALLNet -} - // SupportUOT implements C.ProxyAdapter func (s *Snell) SupportUOT() bool { return true @@ -194,30 +165,24 @@ func NewSnell(option SnellOption) (*Snell, error) { name: option.Name, addr: addr, tp: C.Snell, + pdName: option.ProviderName, udp: option.UDP, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, psk: psk, obfsOption: obfsOption, version: option.Version, } + s.dialer = option.NewDialer(s.DialOptions()) if option.Version == snell.Version2 { s.pool = snell.NewPool(func(ctx context.Context) (*snell.Snell, error) { - var err error - var cDialer C.Dialer = dialer.NewDialer(s.DialOptions()...) - if len(s.option.DialerProxy) > 0 { - cDialer, err = proxydialer.NewByName(s.option.DialerProxy, cDialer) - if err != nil { - return nil, err - } - } - c, err := cDialer.DialContext(ctx, "tcp", addr) + c, err := s.dialer.DialContext(ctx, "tcp", addr) if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/socks5.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/socks5.go index 00e096c36c..f27f6de8bf 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/socks5.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/socks5.go @@ -2,7 +2,6 @@ package outbound import ( "context" - "crypto/tls" "errors" "fmt" "io" @@ -12,10 +11,10 @@ import ( N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/ca" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/socks5" + + "github.com/metacubex/tls" ) type Socks5 struct { @@ -69,18 +68,7 @@ func (ss *Socks5) StreamConnContext(ctx context.Context, c net.Conn, metadata *C // DialContext implements C.ProxyAdapter func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) { - return ss.DialContextWithDialer(ctx, dialer.NewDialer(ss.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - if len(ss.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } - c, err := dialer.DialContext(ctx, "tcp", ss.addr) + c, err := ss.dialer.DialContext(ctx, "tcp", ss.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } @@ -97,24 +85,12 @@ func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, me return NewConn(c, ss), nil } -// SupportWithDialer implements C.ProxyAdapter -func (ss *Socks5) SupportWithDialer() C.NetWork { - return C.TCP -} - // ListenPacketContext implements C.ProxyAdapter func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) { - var cDialer C.Dialer = dialer.NewDialer(ss.DialOptions()...) - if len(ss.option.DialerProxy) > 0 { - cDialer, err = proxydialer.NewByName(ss.option.DialerProxy, cDialer) - if err != nil { - return nil, err - } - } if err = ss.ResolveUDP(ctx, metadata); err != nil { return nil, err } - c, err := cDialer.DialContext(ctx, "tcp", ss.addr) + c, err := ss.dialer.DialContext(ctx, "tcp", ss.addr) if err != nil { err = fmt.Errorf("%s connect error: %w", ss.addr, err) return @@ -161,7 +137,7 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata) bindUDPAddr.IP = serverAddr.IP } - pc, err := cDialer.ListenPacket(ctx, "udp", "", bindUDPAddr.AddrPort()) + pc, err := ss.dialer.ListenPacket(ctx, "udp", "", bindUDPAddr.AddrPort()) if err != nil { return } @@ -210,17 +186,18 @@ func NewSocks5(option Socks5Option) (*Socks5, error) { } } - return &Socks5{ + outbound := &Socks5{ Base: &Base{ name: option.Name, addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.Socks5, + pdName: option.ProviderName, udp: option.UDP, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, user: option.UserName, @@ -228,7 +205,9 @@ func NewSocks5(option Socks5Option) (*Socks5, error) { tls: option.TLS, skipCertVerify: option.SkipCertVerify, tlsConfig: tlsConfig, - }, nil + } + outbound.dialer = option.NewDialer(outbound.DialOptions()) + return outbound, nil } type socksPacketConn struct { diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/ssh.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/ssh.go index 3b9151474f..5dca2b1720 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/ssh.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/ssh.go @@ -12,8 +12,6 @@ import ( "sync" N "github.com/metacubex/mihomo/common/net" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/randv2" @@ -44,14 +42,7 @@ type SshOption struct { } func (s *Ssh) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) { - var cDialer C.Dialer = dialer.NewDialer(s.DialOptions()...) - if len(s.option.DialerProxy) > 0 { - cDialer, err = proxydialer.NewByName(s.option.DialerProxy, cDialer) - if err != nil { - return nil, err - } - } - client, err := s.connect(ctx, cDialer, s.addr) + client, err := s.connect(ctx, s.addr) if err != nil { return nil, err } @@ -63,13 +54,13 @@ func (s *Ssh) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, return NewConn(c, s), nil } -func (s *Ssh) connect(ctx context.Context, cDialer C.Dialer, addr string) (client *ssh.Client, err error) { +func (s *Ssh) connect(ctx context.Context, addr string) (client *ssh.Client, err error) { s.cMutex.Lock() defer s.cMutex.Unlock() if s.client != nil { return s.client, nil } - c, err := cDialer.DialContext(ctx, "tcp", addr) + c, err := s.dialer.DialContext(ctx, "tcp", addr) if err != nil { return nil, err } @@ -195,14 +186,15 @@ func NewSsh(option SshOption) (*Ssh, error) { name: option.Name, addr: addr, tp: C.Ssh, + pdName: option.ProviderName, udp: false, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, config: &config, } - + outbound.dialer = option.NewDialer(outbound.DialOptions()) return outbound, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/sudoku.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/sudoku.go index 9b4a9c9db1..bd393ec616 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/sudoku.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/sudoku.go @@ -2,68 +2,47 @@ package outbound import ( "context" - "crypto/sha256" - "encoding/binary" "fmt" - "io" "net" "strconv" "strings" - "time" - - "github.com/metacubex/mihomo/log" - - "github.com/saba-futai/sudoku/apis" - "github.com/saba-futai/sudoku/pkg/crypto" - "github.com/saba-futai/sudoku/pkg/obfs/httpmask" - "github.com/saba-futai/sudoku/pkg/obfs/sudoku" N "github.com/metacubex/mihomo/common/net" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/proxydialer" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/sudoku" ) type Sudoku struct { *Base option *SudokuOption - table *sudoku.Table - baseConf apis.ProtocolConfig + baseConf sudoku.ProtocolConfig } type SudokuOption struct { BasicOption - Name string `proxy:"name"` - Server string `proxy:"server"` - Port int `proxy:"port"` - Key string `proxy:"key"` - AEADMethod string `proxy:"aead-method,omitempty"` - PaddingMin *int `proxy:"padding-min,omitempty"` - PaddingMax *int `proxy:"padding-max,omitempty"` - TableType string `proxy:"table-type,omitempty"` // "prefer_ascii" or "prefer_entropy" - HTTPMask bool `proxy:"http-mask,omitempty"` + Name string `proxy:"name"` + Server string `proxy:"server"` + Port int `proxy:"port"` + Key string `proxy:"key"` + AEADMethod string `proxy:"aead-method,omitempty"` + PaddingMin *int `proxy:"padding-min,omitempty"` + PaddingMax *int `proxy:"padding-max,omitempty"` + TableType string `proxy:"table-type,omitempty"` // "prefer_ascii" or "prefer_entropy" + EnablePureDownlink *bool `proxy:"enable-pure-downlink,omitempty"` + HTTPMask bool `proxy:"http-mask,omitempty"` + HTTPMaskStrategy string `proxy:"http-mask-strategy,omitempty"` // "random" (default), "post", "websocket" + CustomTable string `proxy:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv + CustomTables []string `proxy:"custom-tables,omitempty"` // optional table rotation patterns, overrides custom-table when non-empty } // DialContext implements C.ProxyAdapter -func (s *Sudoku) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) { - return s.DialContextWithDialer(ctx, dialer.NewDialer(s.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (s *Sudoku) DialContextWithDialer(ctx context.Context, d C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - if len(s.option.DialerProxy) > 0 { - d, err = proxydialer.NewByName(s.option.DialerProxy, d) - if err != nil { - return nil, err - } - } - +func (s *Sudoku) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn, err error) { cfg, err := s.buildConfig(metadata) if err != nil { return nil, err } - c, err := d.DialContext(ctx, "tcp", s.addr) + c, err := s.dialer.DialContext(ctx, "tcp", s.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", s.addr, err) } @@ -77,27 +56,69 @@ func (s *Sudoku) DialContextWithDialer(ctx context.Context, d C.Dialer, metadata defer done(&err) } - c, err = s.streamConn(c, cfg) + c, err = sudoku.ClientHandshakeWithOptions(c, cfg, sudoku.ClientHandshakeOptions{ + HTTPMaskStrategy: s.option.HTTPMaskStrategy, + }) if err != nil { return nil, err } + addrBuf, err := sudoku.EncodeAddress(cfg.TargetAddress) + if err != nil { + return nil, fmt.Errorf("encode target address failed: %w", err) + } + + if _, err = c.Write(addrBuf); err != nil { + _ = c.Close() + return nil, fmt.Errorf("send target address failed: %w", err) + } + return NewConn(c, s), nil } // ListenPacketContext implements C.ProxyAdapter func (s *Sudoku) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) { - return nil, C.ErrNotSupport + if err := s.ResolveUDP(ctx, metadata); err != nil { + return nil, err + } + + cfg, err := s.buildConfig(metadata) + if err != nil { + return nil, err + } + + c, err := s.dialer.DialContext(ctx, "tcp", s.addr) + if err != nil { + return nil, fmt.Errorf("%s connect error: %w", s.addr, err) + } + + defer func() { + safeConnClose(c, err) + }() + + if ctx.Done() != nil { + done := N.SetupContextForConn(ctx, c) + defer done(&err) + } + + c, err = sudoku.ClientHandshakeWithOptions(c, cfg, sudoku.ClientHandshakeOptions{ + HTTPMaskStrategy: s.option.HTTPMaskStrategy, + }) + if err != nil { + return nil, err + } + + if err = sudoku.WritePreface(c); err != nil { + _ = c.Close() + return nil, fmt.Errorf("send uot preface failed: %w", err) + } + + return newPacketConn(N.NewThreadSafePacketConn(sudoku.NewUoTPacketConn(c)), s), nil } // SupportUOT implements C.ProxyAdapter func (s *Sudoku) SupportUOT() bool { - return false // Sudoku protocol only supports TCP -} - -// SupportWithDialer implements C.ProxyAdapter -func (s *Sudoku) SupportWithDialer() C.NetWork { - return C.TCP + return true } // ProxyInfo implements C.ProxyAdapter @@ -107,7 +128,7 @@ func (s *Sudoku) ProxyInfo() C.ProxyInfo { return info } -func (s *Sudoku) buildConfig(metadata *C.Metadata) (*apis.ProtocolConfig, error) { +func (s *Sudoku) buildConfig(metadata *C.Metadata) (*sudoku.ProtocolConfig, error) { if metadata == nil || metadata.DstPort == 0 || !metadata.Valid() { return nil, fmt.Errorf("invalid metadata for sudoku outbound") } @@ -121,33 +142,6 @@ func (s *Sudoku) buildConfig(metadata *C.Metadata) (*apis.ProtocolConfig, error) return &cfg, nil } -func (s *Sudoku) streamConn(rawConn net.Conn, cfg *apis.ProtocolConfig) (_ net.Conn, err error) { - if !cfg.DisableHTTPMask { - if err = httpmask.WriteRandomRequestHeader(rawConn, cfg.ServerAddress); err != nil { - return nil, fmt.Errorf("write http mask failed: %w", err) - } - } - - obfsConn := sudoku.NewConn(rawConn, cfg.Table, cfg.PaddingMin, cfg.PaddingMax, false) - cConn, err := crypto.NewAEADConn(obfsConn, cfg.Key, cfg.AEADMethod) - if err != nil { - return nil, fmt.Errorf("setup crypto failed: %w", err) - } - - handshake := buildSudokuHandshakePayload(cfg.Key) - if _, err = cConn.Write(handshake[:]); err != nil { - cConn.Close() - return nil, fmt.Errorf("send handshake failed: %w", err) - } - - if err = writeTargetAddress(cConn, cfg.TargetAddress); err != nil { - cConn.Close() - return nil, fmt.Errorf("send target address failed: %w", err) - } - - return cConn, nil -} - func NewSudoku(option SudokuOption) (*Sudoku, error) { if option.Server == "" { return nil, fmt.Errorf("server is required") @@ -167,16 +161,7 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) { return nil, fmt.Errorf("table-type must be prefer_ascii or prefer_entropy") } - seed := option.Key - if recoveredFromKey, err := crypto.RecoverPublicKey(option.Key); err == nil { - seed = crypto.EncodePoint(recoveredFromKey) - } - - start := time.Now() - table := sudoku.NewTable(seed, tableType) - log.Infoln("[Sudoku] Tables initialized (%s) in %v", tableType, time.Since(start)) - - defaultConf := apis.DefaultConfig() + defaultConf := sudoku.DefaultConfig() paddingMin := defaultConf.PaddingMin paddingMax := defaultConf.PaddingMax if option.PaddingMin != nil { @@ -191,80 +176,50 @@ func NewSudoku(option SudokuOption) (*Sudoku, error) { if option.PaddingMax == nil && option.PaddingMin != nil && paddingMax < paddingMin { paddingMax = paddingMin } + enablePureDownlink := defaultConf.EnablePureDownlink + if option.EnablePureDownlink != nil { + enablePureDownlink = *option.EnablePureDownlink + } - baseConf := apis.ProtocolConfig{ + baseConf := sudoku.ProtocolConfig{ ServerAddress: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), Key: option.Key, AEADMethod: defaultConf.AEADMethod, - Table: table, PaddingMin: paddingMin, PaddingMax: paddingMax, + EnablePureDownlink: enablePureDownlink, HandshakeTimeoutSeconds: defaultConf.HandshakeTimeoutSeconds, DisableHTTPMask: !option.HTTPMask, } + tables, err := sudoku.NewTablesWithCustomPatterns(sudoku.ClientAEADSeed(option.Key), tableType, option.CustomTable, option.CustomTables) + if err != nil { + return nil, fmt.Errorf("build table(s) failed: %w", err) + } + if len(tables) == 1 { + baseConf.Table = tables[0] + } else { + baseConf.Tables = tables + } if option.AEADMethod != "" { baseConf.AEADMethod = option.AEADMethod } - return &Sudoku{ + outbound := &Sudoku{ Base: &Base{ name: option.Name, addr: baseConf.ServerAddress, tp: C.Sudoku, - udp: false, + pdName: option.ProviderName, + udp: true, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, - table: table, baseConf: baseConf, - }, nil -} - -func buildSudokuHandshakePayload(key string) [16]byte { - var payload [16]byte - binary.BigEndian.PutUint64(payload[:8], uint64(time.Now().Unix())) - hash := sha256.Sum256([]byte(key)) - copy(payload[8:], hash[:8]) - return payload -} - -func writeTargetAddress(w io.Writer, rawAddr string) error { - host, portStr, err := net.SplitHostPort(rawAddr) - if err != nil { - return err } - - portInt, err := net.LookupPort("tcp", portStr) - if err != nil { - return err - } - - var buf []byte - if ip := net.ParseIP(host); ip != nil { - if ip4 := ip.To4(); ip4 != nil { - buf = append(buf, 0x01) // IPv4 - buf = append(buf, ip4...) - } else { - buf = append(buf, 0x04) // IPv6 - buf = append(buf, ip...) - } - } else { - if len(host) > 255 { - return fmt.Errorf("domain too long") - } - buf = append(buf, 0x03) // domain - buf = append(buf, byte(len(host))) - buf = append(buf, host...) - } - - var portBytes [2]byte - binary.BigEndian.PutUint16(portBytes[:], uint16(portInt)) - buf = append(buf, portBytes[:]...) - - _, err = w.Write(buf) - return err + outbound.dialer = option.NewDialer(outbound.DialOptions()) + return outbound, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/trojan.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/trojan.go index 5e0de39c9e..3390c57709 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/trojan.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/trojan.go @@ -2,24 +2,23 @@ package outbound import ( "context" - "crypto/tls" "errors" "fmt" "net" - "net/http" "strconv" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/ca" - "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/ech" - "github.com/metacubex/mihomo/component/proxydialer" tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/gun" "github.com/metacubex/mihomo/transport/shadowsocks/core" "github.com/metacubex/mihomo/transport/trojan" "github.com/metacubex/mihomo/transport/vmess" + + "github.com/metacubex/http" + "github.com/metacubex/tls" ) type Trojan struct { @@ -196,18 +195,7 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con return NewConn(c, t), nil } - return t.DialContextWithDialer(ctx, dialer.NewDialer(t.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - if len(t.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } - c, err := dialer.DialContext(ctx, "tcp", t.addr) + c, err = t.dialer.DialContext(ctx, "tcp", t.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } @@ -250,21 +238,10 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata) pc := trojan.NewPacketConn(c) return newPacketConn(pc, t), err } - return t.ListenPacketWithDialer(ctx, dialer.NewDialer(t.DialOptions()...), metadata) -} - -// ListenPacketWithDialer implements C.ProxyAdapter -func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - if len(t.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } if err = t.ResolveUDP(ctx, metadata); err != nil { return nil, err } - c, err := dialer.DialContext(ctx, "tcp", t.addr) + c, err = t.dialer.DialContext(ctx, "tcp", t.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } @@ -280,11 +257,6 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me return newPacketConn(pc, t), err } -// SupportWithDialer implements C.ProxyAdapter -func (t *Trojan) SupportWithDialer() C.NetWork { - return C.ALLNet -} - // SupportUOT implements C.ProxyAdapter func (t *Trojan) SupportUOT() bool { return true @@ -317,16 +289,18 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { name: option.Name, addr: addr, tp: C.Trojan, + pdName: option.ProviderName, udp: option.UDP, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, hexPassword: trojan.Key(option.Password), } + t.dialer = option.NewDialer(t.DialOptions()) var err error t.realityConfig, err = option.RealityOpts.Parse() @@ -355,15 +329,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { if option.Network == "grpc" { dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) { - var err error - var cDialer C.Dialer = dialer.NewDialer(t.DialOptions()...) - if len(t.option.DialerProxy) > 0 { - cDialer, err = proxydialer.NewByName(t.option.DialerProxy, cDialer) - if err != nil { - return nil, err - } - } - c, err := cDialer.DialContext(ctx, "tcp", t.addr) + c, err := t.dialer.DialContext(ctx, "tcp", t.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", t.addr, err.Error()) } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/tuic.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/tuic.go index f76f482f57..fd1268ad1e 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/tuic.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/tuic.go @@ -2,7 +2,6 @@ package outbound import ( "context" - "crypto/tls" "fmt" "math" "net" @@ -10,10 +9,7 @@ import ( "time" "github.com/metacubex/mihomo/component/ca" - "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/ech" - "github.com/metacubex/mihomo/component/proxydialer" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/tuic" @@ -21,6 +17,7 @@ import ( "github.com/metacubex/quic-go" M "github.com/metacubex/sing/common/metadata" "github.com/metacubex/sing/common/uot" + "github.com/metacubex/tls" ) type Tuic struct { @@ -28,7 +25,7 @@ type Tuic struct { option *TuicOption client *tuic.PoolClient - tlsConfig *tlsC.Config + tlsConfig *tls.Config echConfig *ech.Config } @@ -70,12 +67,7 @@ type TuicOption struct { // DialContext implements C.ProxyAdapter func (t *Tuic) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) { - return t.DialContextWithDialer(ctx, dialer.NewDialer(t.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (t *Tuic) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (C.Conn, error) { - conn, err := t.client.DialContextWithDialer(ctx, metadata, dialer, t.dialWithDialer) + conn, err := t.client.DialContext(ctx, metadata) if err != nil { return nil, err } @@ -84,11 +76,6 @@ func (t *Tuic) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad // ListenPacketContext implements C.ProxyAdapter func (t *Tuic) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) { - return t.ListenPacketWithDialer(ctx, dialer.NewDialer(t.DialOptions()...), metadata) -} - -// ListenPacketWithDialer implements C.ProxyAdapter -func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { if err = t.ResolveUDP(ctx, metadata); err != nil { return nil, err } @@ -98,7 +85,7 @@ func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, meta uotMetadata := *metadata uotMetadata.Host = uotDestination.Fqdn uotMetadata.DstPort = uotDestination.Port - c, err := t.DialContextWithDialer(ctx, dialer, &uotMetadata) + c, err := t.DialContext(ctx, &uotMetadata) if err != nil { return nil, err } @@ -112,25 +99,14 @@ func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, meta return newPacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination}), t), nil } } - pc, err := t.client.ListenPacketWithDialer(ctx, metadata, dialer, t.dialWithDialer) + pc, err := t.client.ListenPacket(ctx, metadata) if err != nil { return nil, err } return newPacketConn(pc, t), nil } -// SupportWithDialer implements C.ProxyAdapter -func (t *Tuic) SupportWithDialer() C.NetWork { - return C.ALLNet -} - -func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) { - if len(t.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer) - if err != nil { - return nil, nil, err - } - } +func (t *Tuic) dial(ctx context.Context) (transport *quic.Transport, addr net.Addr, err error) { udpAddr, err := resolveUDPAddr(ctx, "udp", t.addr, t.prefer) if err != nil { return nil, nil, err @@ -141,7 +117,7 @@ func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (transport * } addr = udpAddr var pc net.PacketConn - pc, err = dialer.ListenPacket(ctx, "udp", "", udpAddr.AddrPort()) + pc, err = t.dialer.ListenPacket(ctx, "udp", "", udpAddr.AddrPort()) if err != nil { return nil, nil, err } @@ -256,7 +232,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { tlsConfig.InsecureSkipVerify = true // tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config } - tlsClientConfig := tlsC.UConfig(tlsConfig) + tlsClientConfig := tlsConfig echConfig, err := option.ECHOpts.Parse() if err != nil { return nil, err @@ -275,16 +251,18 @@ func NewTuic(option TuicOption) (*Tuic, error) { name: option.Name, addr: addr, tp: C.Tuic, + pdName: option.ProviderName, udp: true, tfo: option.FastOpen, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, option: &option, tlsConfig: tlsClientConfig, echConfig: echConfig, } + t.dialer = option.NewDialer(t.DialOptions()) clientMaxOpenStreams := int64(option.MaxOpenStreams) @@ -313,7 +291,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { CWND: option.CWND, } - t.client = tuic.NewPoolClientV4(clientOption) + t.client = tuic.NewPoolClientV4(clientOption, t.dial) } else { maxUdpRelayPacketSize := option.MaxUdpRelayPacketSize if maxUdpRelayPacketSize > tuic.MaxFragSizeV5 { @@ -332,7 +310,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { CWND: option.CWND, } - t.client = tuic.NewPoolClientV5(clientOption) + t.client = tuic.NewPoolClientV5(clientOption, t.dial) } return t, nil diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vless.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vless.go index 00e46fdd8c..3ca1bb9f79 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vless.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vless.go @@ -2,19 +2,15 @@ package outbound import ( "context" - "crypto/tls" "fmt" "net" - "net/http" "strconv" "github.com/metacubex/mihomo/common/convert" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/ca" - "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/ech" - "github.com/metacubex/mihomo/component/proxydialer" tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/gun" @@ -22,9 +18,11 @@ import ( "github.com/metacubex/mihomo/transport/vless/encryption" "github.com/metacubex/mihomo/transport/vmess" + "github.com/metacubex/http" vmessSing "github.com/metacubex/sing-vmess" "github.com/metacubex/sing-vmess/packetaddr" M "github.com/metacubex/sing/common/metadata" + "github.com/metacubex/tls" ) type Vless struct { @@ -252,18 +250,7 @@ func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn return NewConn(c, v), nil } - return v.DialContextWithDialer(ctx, dialer.NewDialer(v.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - if len(v.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } - c, err := dialer.DialContext(ctx, "tcp", v.addr) + c, err = v.dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } @@ -301,23 +288,12 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata) ( return v.ListenPacketOnStreamConn(ctx, c, metadata) } - return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.DialOptions()...), metadata) -} - -// ListenPacketWithDialer implements C.ProxyAdapter -func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - if len(v.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } if err = v.ResolveUDP(ctx, metadata); err != nil { return nil, err } - c, err := dialer.DialContext(ctx, "tcp", v.addr) + c, err = v.dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } @@ -333,11 +309,6 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met return v.ListenPacketOnStreamConn(ctx, c, metadata) } -// SupportWithDialer implements C.ProxyAdapter -func (v *Vless) SupportWithDialer() C.NetWork { - return C.ALLNet -} - // ListenPacketOnStreamConn implements C.ProxyAdapter func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { if err = v.ResolveUDP(ctx, metadata); err != nil { @@ -446,17 +417,19 @@ func NewVless(option VlessOption) (*Vless, error) { name: option.Name, addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.Vless, + pdName: option.ProviderName, udp: option.UDP, xudp: option.XUDP, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, client: client, option: &option, } + v.dialer = option.NewDialer(v.DialOptions()) v.encryption, err = encryption.NewClient(option.Encryption) if err != nil { @@ -480,15 +453,7 @@ func NewVless(option VlessOption) (*Vless, error) { } case "grpc": dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) { - var err error - var cDialer C.Dialer = dialer.NewDialer(v.DialOptions()...) - if len(v.option.DialerProxy) > 0 { - cDialer, err = proxydialer.NewByName(v.option.DialerProxy, cDialer) - if err != nil { - return nil, err - } - } - c, err := cDialer.DialContext(ctx, "tcp", v.addr) + c, err := v.dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vmess.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vmess.go index c4badf9983..5654cd7c48 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vmess.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/vmess.go @@ -2,11 +2,9 @@ package outbound import ( "context" - "crypto/tls" "errors" "fmt" "net" - "net/http" "strconv" "strings" "sync" @@ -14,18 +12,18 @@ import ( N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/ca" - "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/ech" - "github.com/metacubex/mihomo/component/proxydialer" tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/ntp" "github.com/metacubex/mihomo/transport/gun" mihomoVMess "github.com/metacubex/mihomo/transport/vmess" + "github.com/metacubex/http" vmess "github.com/metacubex/sing-vmess" "github.com/metacubex/sing-vmess/packetaddr" M "github.com/metacubex/sing/common/metadata" + "github.com/metacubex/tls" ) var ErrUDPRemoteAddrMismatch = errors.New("udp packet dropped due to mismatched remote address") @@ -313,18 +311,7 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Conn return NewConn(c, v), nil } - return v.DialContextWithDialer(ctx, dialer.NewDialer(v.DialOptions()...), metadata) -} - -// DialContextWithDialer implements C.ProxyAdapter -func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - if len(v.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } - c, err := dialer.DialContext(ctx, "tcp", v.addr) + c, err = v.dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } @@ -358,23 +345,12 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) ( } return v.ListenPacketOnStreamConn(ctx, c, metadata) } - return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.DialOptions()...), metadata) -} - -// ListenPacketWithDialer implements C.ProxyAdapter -func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - if len(v.option.DialerProxy) > 0 { - dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) - if err != nil { - return nil, err - } - } if err = v.ResolveUDP(ctx, metadata); err != nil { return nil, err } - c, err := dialer.DialContext(ctx, "tcp", v.addr) + c, err = v.dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } @@ -389,11 +365,6 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met return v.ListenPacketOnStreamConn(ctx, c, metadata) } -// SupportWithDialer implements C.ProxyAdapter -func (v *Vmess) SupportWithDialer() C.NetWork { - return C.ALLNet -} - // ProxyInfo implements C.ProxyAdapter func (v *Vmess) ProxyInfo() C.ProxyInfo { info := v.Base.ProxyInfo() @@ -456,17 +427,19 @@ func NewVmess(option VmessOption) (*Vmess, error) { name: option.Name, addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.Vmess, + pdName: option.ProviderName, udp: option.UDP, xudp: option.XUDP, tfo: option.TFO, mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, client: client, option: &option, } + v.dialer = option.NewDialer(v.DialOptions()) v.realityConfig, err = v.option.RealityOpts.Parse() if err != nil { @@ -485,15 +458,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { } case "grpc": dialFn := func(ctx context.Context, network, addr string) (net.Conn, error) { - var err error - var cDialer C.Dialer = dialer.NewDialer(v.DialOptions()...) - if len(v.option.DialerProxy) > 0 { - cDialer, err = proxydialer.NewByName(v.option.DialerProxy, cDialer) - if err != nil { - return nil, err - } - } - c, err := cDialer.DialContext(ctx, "tcp", v.addr) + c, err := v.dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/wireguard.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/wireguard.go index ba6e99ee1b..242d0c9fad 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/wireguard.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outbound/wireguard.go @@ -40,7 +40,6 @@ type WireGuard struct { bind *wireguard.ClientBind device wireguardGoDevice tunDevice wireguard.Device - dialer proxydialer.SingDialer resolver resolver.Resolver initOk atomic.Bool @@ -171,14 +170,15 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { name: option.Name, addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.WireGuard, + pdName: option.ProviderName, udp: option.UDP, iface: option.Interface, rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), + prefer: option.IPVersion, }, } - singDialer := proxydialer.NewSlowDownSingDialer(proxydialer.NewByNameSingDialer(option.DialerProxy, dialer.NewDialer(outbound.DialOptions()...)), slowdown.New()) - outbound.dialer = singDialer + outbound.dialer = option.NewDialer(outbound.DialOptions()) + singDialer := proxydialer.NewSlowDownSingDialer(proxydialer.NewSingDialer(outbound.dialer), slowdown.New()) var reserved [3]uint8 if len(option.Reserved) > 0 { @@ -196,7 +196,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { outbound.connectAddr = option.Addr() } } - outbound.bind = wireguard.NewClientBind(context.Background(), wgSingErrorHandler{outbound.Name()}, outbound.dialer, isConnect, outbound.connectAddr.AddrPort(), reserved) + outbound.bind = wireguard.NewClientBind(context.Background(), wgSingErrorHandler{outbound.Name()}, singDialer, isConnect, outbound.connectAddr.AddrPort(), reserved) var err error outbound.localPrefixes, err = option.Prefixes() @@ -609,6 +609,13 @@ func (w *WireGuard) ResolveUDP(ctx context.Context, metadata *C.Metadata) error return nil } +// ProxyInfo implements C.ProxyAdapter +func (w *WireGuard) ProxyInfo() C.ProxyInfo { + info := w.Base.ProxyInfo() + info.DialerProxy = w.option.DialerProxy + return info +} + // IsL3Protocol implements C.ProxyAdapter func (w *WireGuard) IsL3Protocol(metadata *C.Metadata) bool { return true diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/fallback.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/fallback.go index 3772107bc1..0174a7b944 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/fallback.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/fallback.go @@ -150,6 +150,14 @@ func (f *Fallback) ForceSet(name string) { f.selected = name } +func (f *Fallback) Providers() []P.ProxyProvider { + return f.providers +} + +func (f *Fallback) Proxies() []C.Proxy { + return f.GetProxies(false) +} + func NewFallback(option *GroupCommonOption, providers []P.ProxyProvider) *Fallback { return &Fallback{ GroupBase: NewGroupBase(GroupBaseOption{ diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/loadbalance.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/loadbalance.go index dff9b5ed9d..19ee38c7de 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/loadbalance.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/loadbalance.go @@ -239,6 +239,18 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) { }) } +func (lb *LoadBalance) Providers() []P.ProxyProvider { + return lb.providers +} + +func (lb *LoadBalance) Proxies() []C.Proxy { + return lb.GetProxies(false) +} + +func (lb *LoadBalance) Now() string { + return "" +} + func NewLoadBalance(option *GroupCommonOption, providers []P.ProxyProvider, strategy string) (lb *LoadBalance, err error) { var strategyFn strategyFn switch strategy { diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/patch_android.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/patch_android.go deleted file mode 100644 index 016ed6067b..0000000000 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/patch_android.go +++ /dev/null @@ -1,64 +0,0 @@ -//go:build android && cmfa - -package outboundgroup - -import ( - C "github.com/metacubex/mihomo/constant" - P "github.com/metacubex/mihomo/constant/provider" -) - -type ProxyGroup interface { - C.ProxyAdapter - - Providers() []P.ProxyProvider - Proxies() []C.Proxy - Now() string -} - -func (f *Fallback) Providers() []P.ProxyProvider { - return f.providers -} - -func (lb *LoadBalance) Providers() []P.ProxyProvider { - return lb.providers -} - -func (f *Fallback) Proxies() []C.Proxy { - return f.GetProxies(false) -} - -func (lb *LoadBalance) Proxies() []C.Proxy { - return lb.GetProxies(false) -} - -func (lb *LoadBalance) Now() string { - return "" -} - -func (r *Relay) Providers() []P.ProxyProvider { - return r.providers -} - -func (r *Relay) Proxies() []C.Proxy { - return r.GetProxies(false) -} - -func (r *Relay) Now() string { - return "" -} - -func (s *Selector) Providers() []P.ProxyProvider { - return s.providers -} - -func (s *Selector) Proxies() []C.Proxy { - return s.GetProxies(false) -} - -func (u *URLTest) Providers() []P.ProxyProvider { - return u.providers -} - -func (u *URLTest) Proxies() []C.Proxy { - return u.GetProxies(false) -} diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/relay.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/relay.go deleted file mode 100644 index 8e93d89837..0000000000 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/relay.go +++ /dev/null @@ -1,163 +0,0 @@ -package outboundgroup - -import ( - "context" - "encoding/json" - - "github.com/metacubex/mihomo/adapter/outbound" - "github.com/metacubex/mihomo/component/dialer" - "github.com/metacubex/mihomo/component/proxydialer" - C "github.com/metacubex/mihomo/constant" - P "github.com/metacubex/mihomo/constant/provider" - "github.com/metacubex/mihomo/log" -) - -type Relay struct { - *GroupBase - Hidden bool - Icon string -} - -// DialContext implements C.ProxyAdapter -func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, error) { - proxies, chainProxies := r.proxies(metadata, true) - - switch len(proxies) { - case 0: - return outbound.NewDirect().DialContext(ctx, metadata) - case 1: - return proxies[0].DialContext(ctx, metadata) - } - var d C.Dialer - d = dialer.NewDialer() - for _, proxy := range proxies[:len(proxies)-1] { - d = proxydialer.New(proxy, d, false) - } - last := proxies[len(proxies)-1] - conn, err := last.DialContextWithDialer(ctx, d, metadata) - if err != nil { - return nil, err - } - - for i := len(chainProxies) - 2; i >= 0; i-- { - conn.AppendToChains(chainProxies[i]) - } - - conn.AppendToChains(r) - - return conn, nil -} - -// ListenPacketContext implements C.ProxyAdapter -func (r *Relay) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) { - proxies, chainProxies := r.proxies(metadata, true) - - switch len(proxies) { - case 0: - return outbound.NewDirect().ListenPacketContext(ctx, metadata) - case 1: - return proxies[0].ListenPacketContext(ctx, metadata) - } - - var d C.Dialer - d = dialer.NewDialer() - for _, proxy := range proxies[:len(proxies)-1] { - d = proxydialer.New(proxy, d, false) - } - last := proxies[len(proxies)-1] - pc, err := last.ListenPacketWithDialer(ctx, d, metadata) - if err != nil { - return nil, err - } - - for i := len(chainProxies) - 2; i >= 0; i-- { - pc.AppendToChains(chainProxies[i]) - } - - pc.AppendToChains(r) - - return pc, nil -} - -// SupportUDP implements C.ProxyAdapter -func (r *Relay) SupportUDP() bool { - proxies, _ := r.proxies(nil, false) - if len(proxies) == 0 { // C.Direct - return true - } - for i := len(proxies) - 1; i >= 0; i-- { - proxy := proxies[i] - if !proxy.SupportUDP() { - return false - } - if proxy.SupportUOT() { - return true - } - switch proxy.SupportWithDialer() { - case C.ALLNet: - case C.UDP: - default: // C.TCP and C.InvalidNet - return false - } - } - return true -} - -// MarshalJSON implements C.ProxyAdapter -func (r *Relay) MarshalJSON() ([]byte, error) { - all := []string{} - for _, proxy := range r.GetProxies(false) { - all = append(all, proxy.Name()) - } - return json.Marshal(map[string]any{ - "type": r.Type().String(), - "all": all, - "hidden": r.Hidden, - "icon": r.Icon, - }) -} - -func (r *Relay) proxies(metadata *C.Metadata, touch bool) ([]C.Proxy, []C.Proxy) { - rawProxies := r.GetProxies(touch) - - var proxies []C.Proxy - var chainProxies []C.Proxy - var targetProxies []C.Proxy - - for n, proxy := range rawProxies { - proxies = append(proxies, proxy) - chainProxies = append(chainProxies, proxy) - subproxy := proxy.Unwrap(metadata, touch) - for subproxy != nil { - chainProxies = append(chainProxies, subproxy) - proxies[n] = subproxy - subproxy = subproxy.Unwrap(metadata, touch) - } - } - - for _, proxy := range proxies { - if proxy.Type() != C.Direct && proxy.Type() != C.Compatible { - targetProxies = append(targetProxies, proxy) - } - } - - return targetProxies, chainProxies -} - -func (r *Relay) Addr() string { - proxies, _ := r.proxies(nil, false) - return proxies[len(proxies)-1].Addr() -} - -func NewRelay(option *GroupCommonOption, providers []P.ProxyProvider) *Relay { - log.Warnln("The group [%s] with relay type is deprecated, please using dialer-proxy instead", option.Name) - return &Relay{ - GroupBase: NewGroupBase(GroupBaseOption{ - Name: option.Name, - Type: C.Relay, - Providers: providers, - }), - Hidden: option.Hidden, - Icon: option.Icon, - } -} diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/selector.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/selector.go index f8975df744..7bc138fdc7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/selector.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/selector.go @@ -108,6 +108,14 @@ func (s *Selector) selectedProxy(touch bool) C.Proxy { return proxies[0] } +func (s *Selector) Providers() []P.ProxyProvider { + return s.providers +} + +func (s *Selector) Proxies() []C.Proxy { + return s.GetProxies(false) +} + func NewSelector(option *GroupCommonOption, providers []P.ProxyProvider) *Selector { return &Selector{ GroupBase: NewGroupBase(GroupBaseOption{ diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/urltest.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/urltest.go index 2adb3b814e..49ea12aa0b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/urltest.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/urltest.go @@ -185,6 +185,14 @@ func (u *URLTest) MarshalJSON() ([]byte, error) { }) } +func (u *URLTest) Providers() []P.ProxyProvider { + return u.providers +} + +func (u *URLTest) Proxies() []C.Proxy { + return u.GetProxies(false) +} + func (u *URLTest) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (map[string]uint16, error) { return u.GroupBase.URLTest(ctx, u.testUrl, expectedStatus) } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/util.go b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/util.go index 66b2510c19..d35ea66f15 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/util.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/outboundgroup/util.go @@ -1,5 +1,29 @@ package outboundgroup +import ( + "context" + + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + P "github.com/metacubex/mihomo/constant/provider" +) + +type ProxyGroup interface { + C.ProxyAdapter + + Providers() []P.ProxyProvider + Proxies() []C.Proxy + Now() string + Touch() + + URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (mp map[string]uint16, err error) +} + +var _ ProxyGroup = (*Fallback)(nil) +var _ ProxyGroup = (*LoadBalance)(nil) +var _ ProxyGroup = (*URLTest)(nil) +var _ ProxyGroup = (*Selector)(nil) + type SelectAble interface { Set(string) error ForceSet(name string) diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/parser.go b/clash-meta-android/core/src/foss/golang/clash/adapter/parser.go index af93ebf49c..08f90afe34 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/parser.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/parser.go @@ -8,146 +8,152 @@ import ( C "github.com/metacubex/mihomo/constant" ) -func ParseProxy(mapping map[string]any) (C.Proxy, error) { +func ParseProxy(mapping map[string]any, options ...ProxyOption) (C.Proxy, error) { decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true, KeyReplacer: structure.DefaultKeyReplacer}) proxyType, existType := mapping["type"].(string) if !existType { return nil, fmt.Errorf("missing type") } + opt := applyProxyOptions(options...) + basicOption := outbound.BasicOption{ + DialerForAPI: opt.DialerForAPI, + ProviderName: opt.ProviderName, + } + var ( proxy outbound.ProxyAdapter err error ) switch proxyType { case "ss": - ssOption := &outbound.ShadowSocksOption{} + ssOption := &outbound.ShadowSocksOption{BasicOption: basicOption} err = decoder.Decode(mapping, ssOption) if err != nil { break } proxy, err = outbound.NewShadowSocks(*ssOption) case "ssr": - ssrOption := &outbound.ShadowSocksROption{} + ssrOption := &outbound.ShadowSocksROption{BasicOption: basicOption} err = decoder.Decode(mapping, ssrOption) if err != nil { break } proxy, err = outbound.NewShadowSocksR(*ssrOption) case "socks5": - socksOption := &outbound.Socks5Option{} + socksOption := &outbound.Socks5Option{BasicOption: basicOption} err = decoder.Decode(mapping, socksOption) if err != nil { break } proxy, err = outbound.NewSocks5(*socksOption) case "http": - httpOption := &outbound.HttpOption{} + httpOption := &outbound.HttpOption{BasicOption: basicOption} err = decoder.Decode(mapping, httpOption) if err != nil { break } proxy, err = outbound.NewHttp(*httpOption) case "vmess": - vmessOption := &outbound.VmessOption{} + vmessOption := &outbound.VmessOption{BasicOption: basicOption} err = decoder.Decode(mapping, vmessOption) if err != nil { break } proxy, err = outbound.NewVmess(*vmessOption) case "vless": - vlessOption := &outbound.VlessOption{} + vlessOption := &outbound.VlessOption{BasicOption: basicOption} err = decoder.Decode(mapping, vlessOption) if err != nil { break } proxy, err = outbound.NewVless(*vlessOption) case "snell": - snellOption := &outbound.SnellOption{} + snellOption := &outbound.SnellOption{BasicOption: basicOption} err = decoder.Decode(mapping, snellOption) if err != nil { break } proxy, err = outbound.NewSnell(*snellOption) case "trojan": - trojanOption := &outbound.TrojanOption{} + trojanOption := &outbound.TrojanOption{BasicOption: basicOption} err = decoder.Decode(mapping, trojanOption) if err != nil { break } proxy, err = outbound.NewTrojan(*trojanOption) case "hysteria": - hyOption := &outbound.HysteriaOption{} + hyOption := &outbound.HysteriaOption{BasicOption: basicOption} err = decoder.Decode(mapping, hyOption) if err != nil { break } proxy, err = outbound.NewHysteria(*hyOption) case "hysteria2": - hyOption := &outbound.Hysteria2Option{} + hyOption := &outbound.Hysteria2Option{BasicOption: basicOption} err = decoder.Decode(mapping, hyOption) if err != nil { break } proxy, err = outbound.NewHysteria2(*hyOption) case "wireguard": - wgOption := &outbound.WireGuardOption{} + wgOption := &outbound.WireGuardOption{BasicOption: basicOption} err = decoder.Decode(mapping, wgOption) if err != nil { break } proxy, err = outbound.NewWireGuard(*wgOption) case "tuic": - tuicOption := &outbound.TuicOption{} + tuicOption := &outbound.TuicOption{BasicOption: basicOption} err = decoder.Decode(mapping, tuicOption) if err != nil { break } proxy, err = outbound.NewTuic(*tuicOption) case "direct": - directOption := &outbound.DirectOption{} + directOption := &outbound.DirectOption{BasicOption: basicOption} err = decoder.Decode(mapping, directOption) if err != nil { break } proxy = outbound.NewDirectWithOption(*directOption) case "dns": - dnsOptions := &outbound.DnsOption{} + dnsOptions := &outbound.DnsOption{BasicOption: basicOption} err = decoder.Decode(mapping, dnsOptions) if err != nil { break } proxy = outbound.NewDnsWithOption(*dnsOptions) case "reject": - rejectOption := &outbound.RejectOption{} + rejectOption := &outbound.RejectOption{BasicOption: basicOption} err = decoder.Decode(mapping, rejectOption) if err != nil { break } proxy = outbound.NewRejectWithOption(*rejectOption) case "ssh": - sshOption := &outbound.SshOption{} + sshOption := &outbound.SshOption{BasicOption: basicOption} err = decoder.Decode(mapping, sshOption) if err != nil { break } proxy, err = outbound.NewSsh(*sshOption) case "mieru": - mieruOption := &outbound.MieruOption{} + mieruOption := &outbound.MieruOption{BasicOption: basicOption} err = decoder.Decode(mapping, mieruOption) if err != nil { break } proxy, err = outbound.NewMieru(*mieruOption) case "anytls": - anytlsOption := &outbound.AnyTLSOption{} + anytlsOption := &outbound.AnyTLSOption{BasicOption: basicOption} err = decoder.Decode(mapping, anytlsOption) if err != nil { break } proxy, err = outbound.NewAnyTLS(*anytlsOption) case "sudoku": - sudokuOption := &outbound.SudokuOption{} + sudokuOption := &outbound.SudokuOption{BasicOption: basicOption} err = decoder.Decode(mapping, sudokuOption) if err != nil { break @@ -178,3 +184,30 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { proxy = outbound.NewAutoCloseProxyAdapter(proxy) return NewProxy(proxy), nil } + +type proxyOption struct { + DialerForAPI C.Dialer + ProviderName string +} + +func applyProxyOptions(options ...ProxyOption) proxyOption { + opt := proxyOption{} + for _, o := range options { + o(&opt) + } + return opt +} + +type ProxyOption func(opt *proxyOption) + +func WithDialerForAPI(dialer C.Dialer) ProxyOption { + return func(opt *proxyOption) { + opt.DialerForAPI = dialer + } +} + +func WithProviderName(name string) ProxyOption { + return func(opt *proxyOption) { + opt.ProviderName = name + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go index d6297b5662..6e0da67837 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go @@ -99,7 +99,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (P.ProxyProvider, e } hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, uint(schema.HealthCheck.TestTimeout), hcInterval, schema.HealthCheck.Lazy, expectedStatus) - parser, err := NewProxiesParser(schema.Filter, schema.ExcludeFilter, schema.ExcludeType, schema.DialerProxy, schema.Override) + parser, err := NewProxiesParser(name, schema.Filter, schema.ExcludeFilter, schema.ExcludeType, schema.DialerProxy, schema.Override) if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go index e5d3b8acd5..ff21fe89bf 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go @@ -4,10 +4,10 @@ import ( "encoding/json" "errors" "fmt" - "net/http" "reflect" "runtime" "strings" + "sync" "time" "github.com/metacubex/mihomo/adapter" @@ -20,6 +20,7 @@ import ( "github.com/metacubex/mihomo/tunnel/statistic" "github.com/dlclark/regexp2" + "github.com/metacubex/http" "gopkg.in/yaml.v3" ) @@ -43,6 +44,7 @@ type providerForApi struct { } type baseProvider struct { + mutex sync.RWMutex name string proxies []C.Proxy healthCheck *HealthCheck @@ -54,6 +56,8 @@ func (bp *baseProvider) Name() string { } func (bp *baseProvider) Version() uint32 { + bp.mutex.RLock() + defer bp.mutex.RUnlock() return bp.version } @@ -73,10 +77,14 @@ func (bp *baseProvider) Type() P.ProviderType { } func (bp *baseProvider) Proxies() []C.Proxy { + bp.mutex.RLock() + defer bp.mutex.RUnlock() return bp.proxies } func (bp *baseProvider) Count() int { + bp.mutex.RLock() + defer bp.mutex.RUnlock() return len(bp.proxies) } @@ -93,6 +101,8 @@ func (bp *baseProvider) RegisterHealthCheckTask(url string, expectedStatus utils } func (bp *baseProvider) setProxies(proxies []C.Proxy) { + bp.mutex.Lock() + defer bp.mutex.Unlock() bp.proxies = proxies bp.version += 1 bp.healthCheck.setProxies(proxies) @@ -156,7 +166,7 @@ func (pp *proxySetProvider) Initial() error { func (pp *proxySetProvider) closeAllConnections() { statistic.DefaultManager.Range(func(c statistic.Tracker) bool { - for _, chain := range c.Chains() { + for _, chain := range c.ProviderChains() { if chain == pp.Name() { _ = c.Close() break @@ -330,7 +340,7 @@ func (cp *CompatibleProvider) Close() error { return cp.compatibleProvider.Close() } -func NewProxiesParser(filter string, excludeFilter string, excludeType string, dialerProxy string, override OverrideSchema) (resource.Parser[[]C.Proxy], error) { +func NewProxiesParser(pdName string, filter string, excludeFilter string, excludeType string, dialerProxy string, override OverrideSchema) (resource.Parser[[]C.Proxy], error) { var excludeTypeArray []string if excludeType != "" { excludeTypeArray = strings.Split(excludeType, "|") @@ -448,7 +458,7 @@ func NewProxiesParser(filter string, excludeFilter string, excludeType string, d } } - proxy, err := adapter.ParseProxy(mapping) + proxy, err := adapter.ParseProxy(mapping, adapter.WithProviderName(pdName)) if err != nil { return nil, fmt.Errorf("proxy %d error: %w", idx, err) } diff --git a/clash-meta-android/core/src/foss/golang/clash/common/convert/util.go b/clash-meta-android/core/src/foss/golang/clash/common/convert/util.go index ab00637493..c944ef18eb 100644 --- a/clash-meta-android/core/src/foss/golang/clash/common/convert/util.go +++ b/clash-meta-android/core/src/foss/golang/clash/common/convert/util.go @@ -2,12 +2,12 @@ package convert import ( "encoding/base64" - "net/http" "strings" "time" "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/http" "github.com/metacubex/randv2" "github.com/metacubex/sing-shadowsocks/shadowimpl" ) diff --git a/clash-meta-android/core/src/foss/golang/clash/common/net/websocket.go b/clash-meta-android/core/src/foss/golang/clash/common/net/websocket.go index b002310a94..c49e60fa05 100644 --- a/clash-meta-android/core/src/foss/golang/clash/common/net/websocket.go +++ b/clash-meta-android/core/src/foss/golang/clash/common/net/websocket.go @@ -1,6 +1,8 @@ package net import ( + "crypto/sha1" + "encoding/base64" "encoding/binary" "math/bits" ) @@ -129,3 +131,13 @@ func MaskWebSocket(key uint32, b []byte) uint32 { return key } + +func GetWebSocketSecAccept(secKey string) string { + const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + const nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize) + p := make([]byte, nonceSize+len(magic)) + copy(p[:nonceSize], secKey) + copy(p[nonceSize:], magic) + sum := sha1.Sum(p) + return base64.StdEncoding.EncodeToString(sum[:]) +} diff --git a/clash-meta-android/core/src/foss/golang/clash/common/structure/structure.go b/clash-meta-android/core/src/foss/golang/clash/common/structure/structure.go index 840e4f6cad..d43dec033e 100644 --- a/clash-meta-android/core/src/foss/golang/clash/common/structure/structure.go +++ b/clash-meta-android/core/src/foss/golang/clash/common/structure/structure.go @@ -517,6 +517,10 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e fieldName = tagValue } + if tagValue == "-" { + continue + } + rawMapKey := reflect.ValueOf(fieldName) rawMapVal := dataVal.MapIndex(rawMapKey) if !rawMapVal.IsValid() { diff --git a/clash-meta-android/core/src/foss/golang/clash/common/structure/structure_test.go b/clash-meta-android/core/src/foss/golang/clash/common/structure/structure_test.go index 06dffd0f32..c79c2eb46f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/common/structure/structure_test.go +++ b/clash-meta-android/core/src/foss/golang/clash/common/structure/structure_test.go @@ -308,3 +308,27 @@ func TestStructure_Ignore(t *testing.T) { assert.Nil(t, err) assert.Equal(t, s.MustIgnore, "oldData") } + +func TestStructure_IgnoreInNest(t *testing.T) { + rawMap := map[string]any{ + "-": "newData", + } + + type TP struct { + MustIgnore string `test:"-"` + } + + s := struct { + TP + }{TP{MustIgnore: "oldData"}} + + err := decoder.Decode(rawMap, &s) + assert.Nil(t, err) + assert.Equal(t, s.MustIgnore, "oldData") + + // test omitempty + delete(rawMap, "-") + err = decoder.Decode(rawMap, &s) + assert.Nil(t, err) + assert.Equal(t, s.MustIgnore, "oldData") +} diff --git a/clash-meta-android/core/src/foss/golang/clash/component/tls/auth.go b/clash-meta-android/core/src/foss/golang/clash/component/ca/auth.go similarity index 64% rename from clash-meta-android/core/src/foss/golang/clash/component/tls/auth.go rename to clash-meta-android/core/src/foss/golang/clash/component/ca/auth.go index bfda9f3553..bd25598900 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/tls/auth.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/ca/auth.go @@ -1,17 +1,17 @@ -package tls +package ca import ( - utls "github.com/metacubex/utls" + "github.com/metacubex/tls" ) -type ClientAuthType = utls.ClientAuthType +type ClientAuthType = tls.ClientAuthType const ( - NoClientCert = utls.NoClientCert - RequestClientCert = utls.RequestClientCert - RequireAnyClientCert = utls.RequireAnyClientCert - VerifyClientCertIfGiven = utls.VerifyClientCertIfGiven - RequireAndVerifyClientCert = utls.RequireAndVerifyClientCert + NoClientCert = tls.NoClientCert + RequestClientCert = tls.RequestClientCert + RequireAnyClientCert = tls.RequireAnyClientCert + VerifyClientCertIfGiven = tls.VerifyClientCertIfGiven + RequireAndVerifyClientCert = tls.RequireAndVerifyClientCert ) func ClientAuthTypeFromString(s string) ClientAuthType { diff --git a/clash-meta-android/core/src/foss/golang/clash/component/ca/config.go b/clash-meta-android/core/src/foss/golang/clash/component/ca/config.go index 8f96f7452e..f50780af9f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/ca/config.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/ca/config.go @@ -1,7 +1,6 @@ package ca import ( - "crypto/tls" "crypto/x509" _ "embed" "errors" @@ -11,8 +10,9 @@ import ( "sync" "github.com/metacubex/mihomo/common/once" - C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/ntp" + + "github.com/metacubex/tls" ) var globalCertPool *x509.CertPool @@ -106,12 +106,13 @@ func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) { } if len(opt.Certificate) > 0 || len(opt.PrivateKey) > 0 { - var cert tls.Certificate - cert, err = LoadTLSKeyPair(opt.Certificate, opt.PrivateKey, C.Path) + certLoader, err := NewTLSKeyPairLoader(opt.Certificate, opt.PrivateKey) if err != nil { return nil, err } - tlsConfig.Certificates = []tls.Certificate{cert} + tlsConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { + return certLoader() + } } return tlsConfig, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/component/ca/keypair.go b/clash-meta-android/core/src/foss/golang/clash/component/ca/keypair.go index cefd0cf667..ff9086d1b7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/ca/keypair.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/ca/keypair.go @@ -7,71 +7,85 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/rsa" - "crypto/tls" "crypto/x509" "encoding/pem" "fmt" "math/big" "os" + "runtime" + "sync" "time" + + C "github.com/metacubex/mihomo/constant" + + "github.com/metacubex/fswatch" + "github.com/metacubex/tls" ) -type Path interface { - Resolve(path string) string - IsSafePath(path string) bool - ErrNotSafePath(path string) error -} - -// LoadTLSKeyPair loads a TLS key pair from the provided certificate and private key data or file paths, supporting fallback resolution. -// Returns a tls.Certificate and an error, where the error indicates issues during parsing or file loading. +// NewTLSKeyPairLoader creates a loader function for TLS key pairs from the provided certificate and private key data or file paths. // If both certificate and privateKey are empty, generates a random TLS RSA key pair. -// Accepts a Path interface for resolving file paths when necessary. -func LoadTLSKeyPair(certificate, privateKey string, path Path) (tls.Certificate, error) { +func NewTLSKeyPairLoader(certificate, privateKey string) (func() (*tls.Certificate, error), error) { if certificate == "" && privateKey == "" { var err error certificate, privateKey, _, err = NewRandomTLSKeyPair(KeyPairTypeRSA) if err != nil { - return tls.Certificate{}, err + return nil, err } } cert, painTextErr := tls.X509KeyPair([]byte(certificate), []byte(privateKey)) if painTextErr == nil { - return cert, nil - } - if path == nil { - return tls.Certificate{}, painTextErr + return func() (*tls.Certificate, error) { + return &cert, nil + }, nil } - certificate = path.Resolve(certificate) - privateKey = path.Resolve(privateKey) + certificate = C.Path.Resolve(certificate) + privateKey = C.Path.Resolve(privateKey) var loadErr error - if !path.IsSafePath(certificate) { - loadErr = path.ErrNotSafePath(certificate) - } else if !path.IsSafePath(privateKey) { - loadErr = path.ErrNotSafePath(privateKey) + if !C.Path.IsSafePath(certificate) { + loadErr = C.Path.ErrNotSafePath(certificate) + } else if !C.Path.IsSafePath(privateKey) { + loadErr = C.Path.ErrNotSafePath(privateKey) } else { cert, loadErr = tls.LoadX509KeyPair(certificate, privateKey) } if loadErr != nil { - return tls.Certificate{}, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error()) + return nil, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error()) } - return cert, nil + gcFlag := new(os.File) + updateMutex := sync.RWMutex{} + if watcher, err := fswatch.NewWatcher(fswatch.Options{Path: []string{certificate, privateKey}, Callback: func(path string) { + updateMutex.Lock() + defer updateMutex.Unlock() + if newCert, err := tls.LoadX509KeyPair(certificate, privateKey); err == nil { + cert = newCert + } + }}); err == nil { + if err = watcher.Start(); err == nil { + runtime.SetFinalizer(gcFlag, func(f *os.File) { + _ = watcher.Close() + }) + } + } + return func() (*tls.Certificate, error) { + defer runtime.KeepAlive(gcFlag) + updateMutex.RLock() + defer updateMutex.RUnlock() + return &cert, nil + }, nil } -func LoadCertificates(certificate string, path Path) (*x509.CertPool, error) { +func LoadCertificates(certificate string) (*x509.CertPool, error) { pool := x509.NewCertPool() if pool.AppendCertsFromPEM([]byte(certificate)) { return pool, nil } painTextErr := fmt.Errorf("invalid certificate: %s", certificate) - if path == nil { - return nil, painTextErr - } - certificate = path.Resolve(certificate) + certificate = C.Path.Resolve(certificate) var loadErr error - if !path.IsSafePath(certificate) { - loadErr = path.ErrNotSafePath(certificate) + if !C.Path.IsSafePath(certificate) { + loadErr = C.Path.ErrNotSafePath(certificate) } else { certPEMBlock, err := os.ReadFile(certificate) if pool.AppendCertsFromPEM(certPEMBlock) { @@ -82,6 +96,9 @@ func LoadCertificates(certificate string, path Path) (*x509.CertPool, error) { if loadErr != nil { return nil, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error()) } + //TODO: support dynamic update pool too + // blocked by: https://github.com/golang/go/issues/64796 + // maybe we can direct add `GetRootCAs` and `GetClientCAs` to ourselves tls fork return pool, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/component/ech/ech.go b/clash-meta-android/core/src/foss/golang/clash/component/ech/ech.go index a4064c8df0..fa685d2d3b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/ech/ech.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/ech/ech.go @@ -5,13 +5,33 @@ import ( "fmt" tlsC "github.com/metacubex/mihomo/component/tls" + "github.com/metacubex/tls" ) type Config struct { GetEncryptedClientHelloConfigList func(ctx context.Context, serverName string) ([]byte, error) } -func (cfg *Config) ClientHandle(ctx context.Context, tlsConfig *tlsC.Config) (err error) { +func (cfg *Config) ClientHandle(ctx context.Context, tlsConfig *tls.Config) (err error) { + if cfg == nil { + return nil + } + echConfigList, err := cfg.GetEncryptedClientHelloConfigList(ctx, tlsConfig.ServerName) + if err != nil { + return fmt.Errorf("resolve ECH config error: %w", err) + } + + tlsConfig.EncryptedClientHelloConfigList = echConfigList + if tlsConfig.MinVersion != 0 && tlsConfig.MinVersion < tls.VersionTLS13 { + tlsConfig.MinVersion = tls.VersionTLS13 + } + if tlsConfig.MaxVersion != 0 && tlsConfig.MaxVersion < tls.VersionTLS13 { + tlsConfig.MaxVersion = tls.VersionTLS13 + } + return nil +} + +func (cfg *Config) ClientHandleUTLS(ctx context.Context, tlsConfig *tlsC.Config) (err error) { if cfg == nil { return nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/component/ech/echparser/echparser.go b/clash-meta-android/core/src/foss/golang/clash/component/ech/echparser/echparser.go new file mode 100644 index 0000000000..4d3b213f9a --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/component/ech/echparser/echparser.go @@ -0,0 +1,147 @@ +package echparser + +import ( + "errors" + "fmt" + + "golang.org/x/crypto/cryptobyte" +) + +// export from std's crypto/tls/ech.go + +const extensionEncryptedClientHello = 0xfe0d + +type ECHCipher struct { + KDFID uint16 + AEADID uint16 +} + +type ECHExtension struct { + Type uint16 + Data []byte +} + +type ECHConfig struct { + raw []byte + + Version uint16 + Length uint16 + + ConfigID uint8 + KemID uint16 + PublicKey []byte + SymmetricCipherSuite []ECHCipher + + MaxNameLength uint8 + PublicName []byte + Extensions []ECHExtension +} + +var ErrMalformedECHConfigList = errors.New("tls: malformed ECHConfigList") + +type EchConfigErr struct { + field string +} + +func (e *EchConfigErr) Error() string { + if e.field == "" { + return "tls: malformed ECHConfig" + } + return fmt.Sprintf("tls: malformed ECHConfig, invalid %s field", e.field) +} + +func ParseECHConfig(enc []byte) (skip bool, ec ECHConfig, err error) { + s := cryptobyte.String(enc) + ec.raw = []byte(enc) + if !s.ReadUint16(&ec.Version) { + return false, ECHConfig{}, &EchConfigErr{"version"} + } + if !s.ReadUint16(&ec.Length) { + return false, ECHConfig{}, &EchConfigErr{"length"} + } + if len(ec.raw) < int(ec.Length)+4 { + return false, ECHConfig{}, &EchConfigErr{"length"} + } + ec.raw = ec.raw[:ec.Length+4] + if ec.Version != extensionEncryptedClientHello { + s.Skip(int(ec.Length)) + return true, ECHConfig{}, nil + } + if !s.ReadUint8(&ec.ConfigID) { + return false, ECHConfig{}, &EchConfigErr{"config_id"} + } + if !s.ReadUint16(&ec.KemID) { + return false, ECHConfig{}, &EchConfigErr{"kem_id"} + } + if !s.ReadUint16LengthPrefixed((*cryptobyte.String)(&ec.PublicKey)) { + return false, ECHConfig{}, &EchConfigErr{"public_key"} + } + var cipherSuites cryptobyte.String + if !s.ReadUint16LengthPrefixed(&cipherSuites) { + return false, ECHConfig{}, &EchConfigErr{"cipher_suites"} + } + for !cipherSuites.Empty() { + var c ECHCipher + if !cipherSuites.ReadUint16(&c.KDFID) { + return false, ECHConfig{}, &EchConfigErr{"cipher_suites kdf_id"} + } + if !cipherSuites.ReadUint16(&c.AEADID) { + return false, ECHConfig{}, &EchConfigErr{"cipher_suites aead_id"} + } + ec.SymmetricCipherSuite = append(ec.SymmetricCipherSuite, c) + } + if !s.ReadUint8(&ec.MaxNameLength) { + return false, ECHConfig{}, &EchConfigErr{"maximum_name_length"} + } + var publicName cryptobyte.String + if !s.ReadUint8LengthPrefixed(&publicName) { + return false, ECHConfig{}, &EchConfigErr{"public_name"} + } + ec.PublicName = publicName + var extensions cryptobyte.String + if !s.ReadUint16LengthPrefixed(&extensions) { + return false, ECHConfig{}, &EchConfigErr{"extensions"} + } + for !extensions.Empty() { + var e ECHExtension + if !extensions.ReadUint16(&e.Type) { + return false, ECHConfig{}, &EchConfigErr{"extensions type"} + } + if !extensions.ReadUint16LengthPrefixed((*cryptobyte.String)(&e.Data)) { + return false, ECHConfig{}, &EchConfigErr{"extensions data"} + } + ec.Extensions = append(ec.Extensions, e) + } + + return false, ec, nil +} + +// ParseECHConfigList parses a draft-ietf-tls-esni-18 ECHConfigList, returning a +// slice of parsed ECHConfigs, in the same order they were parsed, or an error +// if the list is malformed. +func ParseECHConfigList(data []byte) ([]ECHConfig, error) { + s := cryptobyte.String(data) + var length uint16 + if !s.ReadUint16(&length) { + return nil, ErrMalformedECHConfigList + } + if length != uint16(len(data)-2) { + return nil, ErrMalformedECHConfigList + } + var configs []ECHConfig + for len(s) > 0 { + if len(s) < 4 { + return nil, errors.New("tls: malformed ECHConfig") + } + configLen := uint16(s[2])<<8 | uint16(s[3]) + skip, ec, err := ParseECHConfig(s) + if err != nil { + return nil, err + } + s = s[configLen+4:] + if !skip { + configs = append(configs, ec) + } + } + return configs, nil +} diff --git a/clash-meta-android/core/src/foss/golang/clash/component/ech/key.go b/clash-meta-android/core/src/foss/golang/clash/component/ech/key.go index afae8098c2..4911b90f4c 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/ech/key.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/ech/key.go @@ -8,10 +8,13 @@ import ( "errors" "fmt" "os" + "runtime" + "sync" - "github.com/metacubex/mihomo/component/ca" - tlsC "github.com/metacubex/mihomo/component/tls" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/fswatch" + "github.com/metacubex/tls" "golang.org/x/crypto/cryptobyte" ) @@ -85,11 +88,11 @@ func GenECHConfig(publicName string) (configBase64 string, keyPem string, err er return } -func UnmarshalECHKeys(raw []byte) ([]tlsC.EncryptedClientHelloKey, error) { - var keys []tlsC.EncryptedClientHelloKey +func UnmarshalECHKeys(raw []byte) ([]tls.EncryptedClientHelloKey, error) { + var keys []tls.EncryptedClientHelloKey rawString := cryptobyte.String(raw) for !rawString.Empty() { - var key tlsC.EncryptedClientHelloKey + var key tls.EncryptedClientHelloKey if !rawString.ReadUint16LengthPrefixed((*cryptobyte.String)(&key.PrivateKey)) { return nil, errors.New("error parsing private key") } @@ -104,40 +107,65 @@ func UnmarshalECHKeys(raw []byte) ([]tlsC.EncryptedClientHelloKey, error) { return keys, nil } -func LoadECHKey(key string, tlsConfig *tlsC.Config, path ca.Path) error { +func LoadECHKey(key string, tlsConfig *tls.Config) error { if key == "" { return nil } - painTextErr := loadECHKey([]byte(key), tlsConfig) + echKeys, painTextErr := loadECHKey([]byte(key)) if painTextErr == nil { + tlsConfig.GetEncryptedClientHelloKeys = func(info *tls.ClientHelloInfo) ([]tls.EncryptedClientHelloKey, error) { + return echKeys, nil + } return nil } - key = path.Resolve(key) + key = C.Path.Resolve(key) var loadErr error - if !path.IsSafePath(key) { - loadErr = path.ErrNotSafePath(key) + if !C.Path.IsSafePath(key) { + loadErr = C.Path.ErrNotSafePath(key) } else { var echKey []byte echKey, loadErr = os.ReadFile(key) if loadErr == nil { - loadErr = loadECHKey(echKey, tlsConfig) + echKeys, loadErr = loadECHKey(echKey) } } if loadErr != nil { return fmt.Errorf("parse ECH keys failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error()) } + gcFlag := new(os.File) + updateMutex := sync.RWMutex{} + if watcher, err := fswatch.NewWatcher(fswatch.Options{Path: []string{key}, Callback: func(path string) { + updateMutex.Lock() + defer updateMutex.Unlock() + if echKey, err := os.ReadFile(key); err == nil { + if newEchKeys, err := loadECHKey(echKey); err == nil { + echKeys = newEchKeys + } + } + }}); err == nil { + if err = watcher.Start(); err == nil { + runtime.SetFinalizer(gcFlag, func(f *os.File) { + _ = watcher.Close() + }) + } + } + tlsConfig.GetEncryptedClientHelloKeys = func(info *tls.ClientHelloInfo) ([]tls.EncryptedClientHelloKey, error) { + defer runtime.KeepAlive(gcFlag) + updateMutex.RLock() + defer updateMutex.RUnlock() + return echKeys, nil + } return nil } -func loadECHKey(echKey []byte, tlsConfig *tlsC.Config) error { +func loadECHKey(echKey []byte) ([]tls.EncryptedClientHelloKey, error) { block, rest := pem.Decode(echKey) if block == nil || block.Type != "ECH KEYS" || len(rest) > 0 { - return errors.New("invalid ECH keys pem") + return nil, errors.New("invalid ECH keys pem") } echKeys, err := UnmarshalECHKeys(block.Bytes) if err != nil { - return fmt.Errorf("parse ECH keys: %w", err) + return nil, fmt.Errorf("parse ECH keys: %w", err) } - tlsConfig.EncryptedClientHelloKeys = echKeys - return nil + return echKeys, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/component/ech/key_test.go b/clash-meta-android/core/src/foss/golang/clash/component/ech/key_test.go new file mode 100644 index 0000000000..d6097aa031 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/component/ech/key_test.go @@ -0,0 +1,30 @@ +package ech + +import ( + "encoding/base64" + "testing" + + "github.com/metacubex/mihomo/component/ech/echparser" +) + +func TestGenECHConfig(t *testing.T) { + domain := "www.example.com" + configBase64, _, err := GenECHConfig(domain) + if err != nil { + t.Error(err) + } + echConfigList, err := base64.StdEncoding.DecodeString(configBase64) + if err != nil { + t.Error(err) + } + echConfigs, err := echparser.ParseECHConfigList(echConfigList) + if err != nil { + t.Error(err) + } + if len(echConfigs) == 0 { + t.Error("no ech config") + } + if publicName := string(echConfigs[0].PublicName); publicName != domain { + t.Error("ech config domain error, expect ", domain, " got", publicName) + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/component/generator/cmd.go b/clash-meta-android/core/src/foss/golang/clash/component/generator/cmd.go index 320bb11d36..1feac0f154 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/generator/cmd.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/generator/cmd.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/metacubex/mihomo/component/ech" + "github.com/metacubex/mihomo/transport/sudoku" "github.com/metacubex/mihomo/transport/vless/encryption" "github.com/gofrs/uuid/v5" @@ -12,7 +13,7 @@ import ( func Main(args []string) { if len(args) < 1 { - panic("Using: generate uuid/reality-keypair/wg-keypair/ech-keypair/vless-mlkem768/vless-x25519") + panic("Using: generate uuid/reality-keypair/wg-keypair/ech-keypair/vless-mlkem768/vless-x25519/sudoku-keypair") } switch args[0] { case "uuid": @@ -69,5 +70,13 @@ func Main(args []string) { fmt.Println("PrivateKey: " + privateKeyBase64) fmt.Println("Password: " + passwordBase64) fmt.Println("Hash32: " + hash32Base64) + case "sudoku-keypair": + privateKey, publicKey, err := sudoku.GenKeyPair() + if err != nil { + panic(err) + } + // Output: Available Private Key for client, Master Public Key for server + fmt.Println("PrivateKey: " + privateKey) + fmt.Println("PublicKey: " + publicKey) } } diff --git a/clash-meta-android/core/src/foss/golang/clash/component/geodata/init.go b/clash-meta-android/core/src/foss/golang/clash/component/geodata/init.go index 08ec1b948d..7b87844249 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/geodata/init.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/geodata/init.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "io" - "net/http" "os" "sync" "time" @@ -14,6 +13,8 @@ import ( "github.com/metacubex/mihomo/component/mmdb" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" + + "github.com/metacubex/http" ) var ( diff --git a/clash-meta-android/core/src/foss/golang/clash/component/http/http.go b/clash-meta-android/core/src/foss/golang/clash/component/http/http.go index 1683c4da38..0592254bb5 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/http/http.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/http/http.go @@ -4,7 +4,6 @@ import ( "context" "io" "net" - "net/http" URL "net/url" "runtime" "strings" @@ -13,6 +12,8 @@ import ( "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/listener/inner" + + "github.com/metacubex/http" ) var ( diff --git a/clash-meta-android/core/src/foss/golang/clash/component/process/process_freebsd_amd64.go b/clash-meta-android/core/src/foss/golang/clash/component/process/process_freebsd_amd64.go index cb43c5ffd3..a6d00c8e15 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/process/process_freebsd_amd64.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/process/process_freebsd_amd64.go @@ -197,6 +197,10 @@ func newSearcher(major int) *searcher { case 12: fallthrough case 13: + fallthrough + case 14: + fallthrough + case 15: s = &searcher{ headSize: 64, tcpItemSize: 744, diff --git a/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/byname.go b/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/byname.go new file mode 100644 index 0000000000..30ade063de --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/byname.go @@ -0,0 +1,37 @@ +package proxydialer + +import ( + "context" + "fmt" + "net" + "net/netip" + + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/tunnel" +) + +type byNameProxyDialer struct { + proxyName string +} + +func (d byNameProxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + proxies := tunnel.Proxies() + proxy, ok := proxies[d.proxyName] + if !ok { + return nil, fmt.Errorf("proxyName[%s] not found", d.proxyName) + } + return New(proxy, true).DialContext(ctx, network, address) +} + +func (d byNameProxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { + proxies := tunnel.Proxies() + proxy, ok := proxies[d.proxyName] + if !ok { + return nil, fmt.Errorf("proxyName[%s] not found", d.proxyName) + } + return New(proxy, true).ListenPacket(ctx, network, address, rAddrPort) +} + +func NewByName(proxyName string) C.Dialer { + return byNameProxyDialer{proxyName: proxyName} +} diff --git a/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/proxydialer.go b/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/proxydialer.go index e3ea300a04..51275038c2 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/proxydialer.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/proxydialer.go @@ -2,34 +2,22 @@ package proxydialer import ( "context" - "fmt" "net" "net/netip" "strings" N "github.com/metacubex/mihomo/common/net" - "github.com/metacubex/mihomo/component/dialer" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/tunnel" "github.com/metacubex/mihomo/tunnel/statistic" ) type proxyDialer struct { proxy C.ProxyAdapter - dialer C.Dialer statistic bool } -func New(proxy C.ProxyAdapter, dialer C.Dialer, statistic bool) C.Dialer { - return proxyDialer{proxy: proxy, dialer: dialer, statistic: statistic} -} - -func NewByName(proxyName string, dialer C.Dialer) (C.Dialer, error) { - proxies := tunnel.Proxies() - if proxy, ok := proxies[proxyName]; ok { - return New(proxy, dialer, true), nil - } - return nil, fmt.Errorf("proxyName[%s] not found", proxyName) +func New(proxy C.ProxyAdapter, statistic bool) C.Dialer { + return proxyDialer{proxy: proxy, statistic: statistic} } func (p proxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { @@ -50,13 +38,7 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( } return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil } - var conn C.Conn - var err error - if _, ok := p.dialer.(dialer.Dialer); ok { // first using old function to let mux work - conn, err = p.proxy.DialContext(ctx, currentMeta) - } else { - conn, err = p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) - } + conn, err := p.proxy.DialContext(ctx, currentMeta) if err != nil { return nil, err } @@ -72,14 +54,8 @@ func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, } func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) (C.PacketConn, error) { - var pc C.PacketConn - var err error currentMeta.NetWork = C.UDP - if _, ok := p.dialer.(dialer.Dialer); ok { // first using old function to let mux work - pc, err = p.proxy.ListenPacketContext(ctx, currentMeta) - } else { - pc, err = p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) - } + pc, err := p.proxy.ListenPacketContext(ctx, currentMeta) if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/sing.go b/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/sing.go index 51d685e8db..9f33246505 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/sing.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/proxydialer/sing.go @@ -12,71 +12,22 @@ import ( type SingDialer interface { N.Dialer - SetDialer(dialer C.Dialer) } -type singDialer proxyDialer +type singDialer struct { + cDialer C.Dialer +} var _ N.Dialer = (*singDialer)(nil) -func (d *singDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - return (*proxyDialer)(d).DialContext(ctx, network, destination.String()) +func (d singDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + return d.cDialer.DialContext(ctx, network, destination.String()) } -func (d *singDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - return (*proxyDialer)(d).ListenPacket(ctx, "udp", "", destination.AddrPort()) +func (d singDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + return d.cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) } -func (d *singDialer) SetDialer(dialer C.Dialer) { - (*proxyDialer)(d).dialer = dialer -} - -func NewSingDialer(proxy C.ProxyAdapter, dialer C.Dialer, statistic bool) SingDialer { - return (*singDialer)(&proxyDialer{ - proxy: proxy, - dialer: dialer, - statistic: statistic, - }) -} - -type byNameSingDialer struct { - dialer C.Dialer - proxyName string -} - -var _ N.Dialer = (*byNameSingDialer)(nil) - -func (d *byNameSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - var cDialer C.Dialer = d.dialer - if len(d.proxyName) > 0 { - pd, err := NewByName(d.proxyName, d.dialer) - if err != nil { - return nil, err - } - cDialer = pd - } - return cDialer.DialContext(ctx, network, destination.String()) -} - -func (d *byNameSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - var cDialer C.Dialer = d.dialer - if len(d.proxyName) > 0 { - pd, err := NewByName(d.proxyName, d.dialer) - if err != nil { - return nil, err - } - cDialer = pd - } - return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) -} - -func (d *byNameSingDialer) SetDialer(dialer C.Dialer) { - d.dialer = dialer -} - -func NewByNameSingDialer(proxyName string, dialer C.Dialer) SingDialer { - return &byNameSingDialer{ - dialer: dialer, - proxyName: proxyName, - } +func NewSingDialer(cDialer C.Dialer) SingDialer { + return singDialer{cDialer: cDialer} } diff --git a/clash-meta-android/core/src/foss/golang/clash/component/resource/vehicle.go b/clash-meta-android/core/src/foss/golang/clash/component/resource/vehicle.go index a34417aab2..86fb3948fe 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/resource/vehicle.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/resource/vehicle.go @@ -4,7 +4,6 @@ import ( "context" "errors" "io" - "net/http" "os" "path/filepath" "time" @@ -13,6 +12,8 @@ import ( mihomoHttp "github.com/metacubex/mihomo/component/http" "github.com/metacubex/mihomo/component/profile/cachefile" P "github.com/metacubex/mihomo/constant/provider" + + "github.com/metacubex/http" ) const ( diff --git a/clash-meta-android/core/src/foss/golang/clash/component/tls/httpserver.go b/clash-meta-android/core/src/foss/golang/clash/component/tls/httpserver.go index 3ddac4d8ee..6a9426d9e3 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/tls/httpserver.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/tls/httpserver.go @@ -3,14 +3,13 @@ package tls import ( "context" "net" - "net/http" "runtime/debug" "time" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/log" - "golang.org/x/net/http2" + "github.com/metacubex/http" ) func extractTlsHandshakeTimeoutFromServer(s *http.Server) time.Duration { @@ -35,8 +34,8 @@ func extractTlsHandshakeTimeoutFromServer(s *http.Server) time.Duration { // only do tls handshake and check NegotiatedProtocol with std's *tls.Conn // so we do the same logic to let http2 (not h2c) work fine func NewListenerForHttps(l net.Listener, httpServer *http.Server, tlsConfig *Config) net.Listener { - http2Server := &http2.Server{} - _ = http2.ConfigureServer(httpServer, http2Server) + http2Server := &http.Http2Server{} + _ = http.Http2ConfigureServer(httpServer, http2Server) return N.NewHandleContextListener(context.Background(), l, func(ctx context.Context, conn net.Conn) (net.Conn, error) { c := Server(conn, tlsConfig) @@ -58,8 +57,8 @@ func NewListenerForHttps(l net.Listener, httpServer *http.Server, tlsConfig *Con _ = conn.SetWriteDeadline(time.Time{}) } - if c.ConnectionState().NegotiatedProtocol == http2.NextProtoTLS { - http2Server.ServeConn(c, &http2.ServeConnOpts{BaseConfig: httpServer}) + if c.ConnectionState().NegotiatedProtocol == http.Http2NextProtoTLS { + http2Server.ServeConn(c, &http.Http2ServeConnOpts{BaseConfig: httpServer}) return nil, net.ErrClosed } return c, nil diff --git a/clash-meta-android/core/src/foss/golang/clash/component/tls/reality.go b/clash-meta-android/core/src/foss/golang/clash/component/tls/reality.go index fe1135f3c4..41079e838e 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/tls/reality.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/tls/reality.go @@ -10,22 +10,21 @@ import ( "crypto/hmac" "crypto/sha256" "crypto/sha512" - "crypto/tls" "crypto/x509" "encoding/binary" "errors" "net" - "net/http" "strings" "time" "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/ntp" + "github.com/metacubex/http" "github.com/metacubex/randv2" + "github.com/metacubex/tls" utls "github.com/metacubex/utls" "golang.org/x/crypto/hkdf" - "golang.org/x/net/http2" ) const RealityMaxShortIDLen = 8 @@ -37,13 +36,14 @@ type RealityConfig struct { SupportX25519MLKEM768 bool } -func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHelloID, tlsConfig *Config, realityConfig *RealityConfig) (net.Conn, error) { +func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHelloID, serverName string, realityConfig *RealityConfig) (net.Conn, error) { for retry := 0; ; retry++ { verifier := &realityVerifier{ - serverName: tlsConfig.ServerName, + serverName: serverName, } uConfig := &utls.Config{ - ServerName: tlsConfig.ServerName, + Time: ntp.Now, + ServerName: serverName, InsecureSkipVerify: true, SessionTicketsDisabled: true, VerifyPeerCertificate: verifier.VerifyPeerCertificate, @@ -132,7 +132,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, fingerprint UClientHello func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) { defer uConn.Close() client := http.Client{ - Transport: &http2.Transport{ + Transport: &http.Http2Transport{ DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) { return uConn, nil }, diff --git a/clash-meta-android/core/src/foss/golang/clash/component/tls/utls.go b/clash-meta-android/core/src/foss/golang/clash/component/tls/utls.go index f68cb997f1..d8ca9716c5 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/tls/utls.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/tls/utls.go @@ -1,13 +1,16 @@ package tls import ( - "crypto/tls" + "context" "net" + "reflect" + "unsafe" "github.com/metacubex/mihomo/common/once" "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/log" + "github.com/metacubex/tls" utls "github.com/metacubex/utls" "github.com/mroth/weightedrand/v2" ) @@ -126,8 +129,11 @@ type EncryptedClientHelloKey = utls.EncryptedClientHelloKey type Config = utls.Config +var tlsCertificateRequestInfoCtxOffset = utils.MustOK(reflect.TypeOf((*tls.CertificateRequestInfo)(nil)).Elem().FieldByName("ctx")).Offset +var tlsClientHelloInfoCtxOffset = utils.MustOK(reflect.TypeOf((*tls.ClientHelloInfo)(nil)).Elem().FieldByName("ctx")).Offset + func UConfig(config *tls.Config) *utls.Config { - return &utls.Config{ + cfg := &utls.Config{ Rand: config.Rand, Time: config.Time, Certificates: utils.Map(config.Certificates, UCertificate), @@ -147,6 +153,52 @@ func UConfig(config *tls.Config) *utls.Config { SessionTicketsDisabled: config.SessionTicketsDisabled, Renegotiation: utls.RenegotiationSupport(config.Renegotiation), } + if config.GetClientCertificate != nil { + cfg.GetClientCertificate = func(info *utls.CertificateRequestInfo) (*utls.Certificate, error) { + tlsInfo := &tls.CertificateRequestInfo{ + AcceptableCAs: info.AcceptableCAs, + SignatureSchemes: utils.Map(info.SignatureSchemes, func(it utls.SignatureScheme) tls.SignatureScheme { + return tls.SignatureScheme(it) + }), + Version: info.Version, + } + *(*context.Context)(unsafe.Add(unsafe.Pointer(tlsInfo), tlsCertificateRequestInfoCtxOffset)) = info.Context() // for tlsInfo.ctx + cert, err := config.GetClientCertificate(tlsInfo) + if err != nil { + return nil, err + } + uCert := UCertificate(*cert) + return &uCert, err + } + } + if config.GetCertificate != nil { + cfg.GetCertificate = func(info *utls.ClientHelloInfo) (*utls.Certificate, error) { + tlsInfo := &tls.ClientHelloInfo{ + CipherSuites: info.CipherSuites, + ServerName: info.ServerName, + SupportedCurves: utils.Map(info.SupportedCurves, func(it utls.CurveID) tls.CurveID { + return tls.CurveID(it) + }), + SupportedPoints: info.SupportedPoints, + SignatureSchemes: utils.Map(info.SignatureSchemes, func(it utls.SignatureScheme) tls.SignatureScheme { + return tls.SignatureScheme(it) + }), + SupportedProtos: info.SupportedProtos, + SupportedVersions: info.SupportedVersions, + Extensions: info.Extensions, + Conn: info.Conn, + //HelloRetryRequest: info.HelloRetryRequest, + } + *(*context.Context)(unsafe.Add(unsafe.Pointer(tlsInfo), tlsClientHelloInfoCtxOffset)) = info.Context() // for tlsInfo.ctx + cert, err := config.GetCertificate(tlsInfo) + if err != nil { + return nil, err + } + uCert := UCertificate(*cert) + return &uCert, err + } + } + return cfg } // BuildWebsocketHandshakeState it will only send http/1.1 in its ALPN. diff --git a/clash-meta-android/core/src/foss/golang/clash/component/updater/update_core.go b/clash-meta-android/core/src/foss/golang/clash/component/updater/update_core.go index ffc4fb0451..83a303af5c 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/updater/update_core.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/updater/update_core.go @@ -6,7 +6,6 @@ import ( "context" "fmt" "io" - "net/http" "os" "os/exec" "path/filepath" @@ -20,6 +19,8 @@ import ( C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/log" + + "github.com/metacubex/http" ) const ( diff --git a/clash-meta-android/core/src/foss/golang/clash/component/updater/utils.go b/clash-meta-android/core/src/foss/golang/clash/component/updater/utils.go index a77c86fe86..58a0a545c0 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/updater/utils.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/updater/utils.go @@ -3,11 +3,12 @@ package updater import ( "context" "io" - "net/http" "os" "time" mihomoHttp "github.com/metacubex/mihomo/component/http" + + "github.com/metacubex/http" ) const defaultHttpTimeout = time.Second * 90 diff --git a/clash-meta-android/core/src/foss/golang/clash/config/config.go b/clash-meta-android/core/src/foss/golang/clash/config/config.go index 301126a61e..c2b5664d3d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/config/config.go +++ b/clash-meta-android/core/src/foss/golang/clash/config/config.go @@ -1292,7 +1292,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro } kLower := strings.ToLower(k) if strings.Contains(kLower, ",") { - if strings.Contains(kLower, "geosite:") { + if strings.HasPrefix(kLower, "geosite:") { subkeys := strings.Split(k, ":") subkeys = subkeys[1:] subkeys = strings.Split(subkeys[0], ",") @@ -1300,7 +1300,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro newKey := "geosite:" + subkey policy = append(policy, dns.Policy{Domain: newKey, NameServers: nameservers}) } - } else if strings.Contains(kLower, "rule-set:") { + } else if strings.HasPrefix(kLower, "rule-set:") { subkeys := strings.Split(k, ":") subkeys = subkeys[1:] subkeys = strings.Split(subkeys[0], ",") @@ -1315,9 +1315,9 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro } } } else { - if strings.Contains(kLower, "geosite:") { + if strings.HasPrefix(kLower, "geosite:") { policy = append(policy, dns.Policy{Domain: "geosite:" + k[8:], NameServers: nameservers}) - } else if strings.Contains(kLower, "rule-set:") { + } else if strings.HasPrefix(kLower, "rule-set:") { policy = append(policy, dns.Policy{Domain: "rule-set:" + k[9:], NameServers: nameservers}) } else { policy = append(policy, dns.Policy{Domain: k, NameServers: nameservers}) @@ -1712,7 +1712,7 @@ func parseSniffer(snifferRaw RawSniffer, ruleProviders map[string]P.RuleProvider } snifferConfig.SkipSrcAddress = skipSrcAddress - skipDstAddress, err := parseIPCIDR(snifferRaw.SkipDstAddress, nil, "sniffer.skip-src-address", ruleProviders) + skipDstAddress, err := parseIPCIDR(snifferRaw.SkipDstAddress, nil, "sniffer.skip-dst-address", ruleProviders) if err != nil { return nil, fmt.Errorf("error in skip-dst-address, error:%w", err) } @@ -1731,7 +1731,7 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string var matcher C.IpMatcher for _, ipcidr := range addresses { ipcidrLower := strings.ToLower(ipcidr) - if strings.Contains(ipcidrLower, "geoip:") { + if strings.HasPrefix(ipcidrLower, "geoip:") { subkeys := strings.Split(ipcidr, ":") subkeys = subkeys[1:] subkeys = strings.Split(subkeys[0], ",") @@ -1742,7 +1742,7 @@ func parseIPCIDR(addresses []string, cidrSet *cidr.IpCidrSet, adapterName string } matchers = append(matchers, matcher) } - } else if strings.Contains(ipcidrLower, "rule-set:") { + } else if strings.HasPrefix(ipcidrLower, "rule-set:") { subkeys := strings.Split(ipcidr, ":") subkeys = subkeys[1:] subkeys = strings.Split(subkeys[0], ",") @@ -1778,7 +1778,7 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte var matcher C.DomainMatcher for _, domain := range domains { domainLower := strings.ToLower(domain) - if strings.Contains(domainLower, "geosite:") { + if strings.HasPrefix(domainLower, "geosite:") { subkeys := strings.Split(domain, ":") subkeys = subkeys[1:] subkeys = strings.Split(subkeys[0], ",") @@ -1789,7 +1789,7 @@ func parseDomain(domains []string, domainTrie *trie.DomainTrie[struct{}], adapte } matchers = append(matchers, matcher) } - } else if strings.Contains(domainLower, "rule-set:") { + } else if strings.HasPrefix(domainLower, "rule-set:") { subkeys := strings.Split(domain, ":") subkeys = subkeys[1:] subkeys = strings.Split(subkeys[0], ",") diff --git a/clash-meta-android/core/src/foss/golang/clash/constant/adapters.go b/clash-meta-android/core/src/foss/golang/clash/constant/adapters.go index 1cd146c107..07ae5de1d8 100644 --- a/clash-meta-android/core/src/foss/golang/clash/constant/adapters.go +++ b/clash-meta-android/core/src/foss/golang/clash/constant/adapters.go @@ -59,6 +59,7 @@ var ErrNotSupport = errors.New("no support") type Connection interface { Chains() Chain + ProviderChains() Chain AppendToChains(adapter ProxyAdapter) RemoteDestination() string } @@ -102,13 +103,14 @@ type Dialer interface { } type ProxyInfo struct { - XUDP bool - TFO bool - MPTCP bool - SMUX bool - Interface string - RoutingMark int - DialerProxy string + XUDP bool + TFO bool + MPTCP bool + SMUX bool + Interface string + RoutingMark int + ProviderName string + DialerProxy string } type ProxyAdapter interface { @@ -121,17 +123,6 @@ type ProxyAdapter interface { ProxyInfo() ProxyInfo MarshalJSON() ([]byte, error) - // Deprecated: use DialContextWithDialer and ListenPacketWithDialer instead. - // StreamConn wraps a protocol around net.Conn with Metadata. - // - // Examples: - // conn, _ := net.DialContext(context.Background(), "tcp", "host:port") - // conn, _ = adapter.StreamConnContext(context.Background(), conn, metadata) - // - // It returns a C.Conn with protocol which start with - // a new session (if any) - StreamConnContext(ctx context.Context, c net.Conn, metadata *Metadata) (net.Conn, error) - // DialContext return a C.Conn with protocol which // contains multiplexing-related reuse logic (if any) DialContext(ctx context.Context, metadata *Metadata) (Conn, error) @@ -140,13 +131,6 @@ type ProxyAdapter interface { // SupportUOT return UDP over TCP support SupportUOT() bool - // SupportWithDialer only for deprecated relay group, the new protocol does not need to be implemented. - SupportWithDialer() NetWork - // DialContextWithDialer only for deprecated relay group, the new protocol does not need to be implemented. - DialContextWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (Conn, error) - // ListenPacketWithDialer only for deprecated relay group, the new protocol does not need to be implemented. - ListenPacketWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (PacketConn, error) - // IsL3Protocol return ProxyAdapter working in L3 (tell dns module not pass the domain to avoid loopback) IsL3Protocol(metadata *Metadata) bool @@ -157,11 +141,6 @@ type ProxyAdapter interface { Close() error } -type Group interface { - URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (mp map[string]uint16, err error) - Touch() -} - type DelayHistory struct { Time time.Time `json:"time"` Delay uint16 `json:"delay"` diff --git a/clash-meta-android/core/src/foss/golang/clash/constant/dns.go b/clash-meta-android/core/src/foss/golang/clash/constant/dns.go index 13a2ed362a..79dafd2bb9 100644 --- a/clash-meta-android/core/src/foss/golang/clash/constant/dns.go +++ b/clash-meta-android/core/src/foss/golang/clash/constant/dns.go @@ -86,12 +86,17 @@ func (d DNSPrefer) String() string { } } -func NewDNSPrefer(prefer string) DNSPrefer { - if p, ok := dnsPreferMap[prefer]; ok { - return p - } else { - return DualStack +func (d DNSPrefer) MarshalText() ([]byte, error) { + return []byte(d.String()), nil +} + +func (d *DNSPrefer) UnmarshalText(data []byte) error { + p, exist := dnsPreferMap[strings.ToLower(string(data))] + if !exist { + p = DualStack } + *d = p + return nil } // FilterModeMapping is a mapping for FilterMode enum diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/client.go b/clash-meta-android/core/src/foss/golang/clash/dns/client.go index 9cc7df2d71..ade44e0890 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/client.go @@ -2,7 +2,6 @@ package dns import ( "context" - "crypto/tls" "fmt" "net" "strings" @@ -12,6 +11,7 @@ import ( C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" + "github.com/metacubex/tls" D "github.com/miekg/dns" ) diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/doh.go b/clash-meta-android/core/src/foss/golang/clash/dns/doh.go index 29be78b2d4..df0697ec55 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/doh.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/doh.go @@ -2,13 +2,11 @@ package dns import ( "context" - "crypto/tls" "encoding/base64" "errors" "fmt" "io" "net" - "net/http" "net/url" "runtime" "strconv" @@ -16,15 +14,15 @@ import ( "time" "github.com/metacubex/mihomo/component/ca" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" + "github.com/metacubex/http" "github.com/metacubex/quic-go" "github.com/metacubex/quic-go/http3" + "github.com/metacubex/tls" D "github.com/miekg/dns" "golang.org/x/exp/slices" - "golang.org/x/net/http2" ) // Values to configure HTTP and HTTP/2 transport. @@ -439,8 +437,8 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp // Explicitly configure transport to use HTTP/2. // // See https://github.com/AdguardTeam/dnsproxy/issues/11. - var transportH2 *http2.Transport - transportH2, err = http2.ConfigureTransports(transport) + var transportH2 *http.Http2Transport + transportH2, err = http.Http2ConfigureTransports(transport) if err != nil { return nil, err } @@ -530,20 +528,20 @@ func (doh *dnsOverHTTPS) createTransportH3( // Ignore the address and always connect to the one that we got // from the bootstrapper. _ string, - tlsCfg *tlsC.Config, + tlsCfg *tls.Config, cfg *quic.Config, ) (c *quic.Conn, err error) { return doh.dialQuic(ctx, addr, tlsCfg, cfg) }, DisableCompression: true, - TLSClientConfig: tlsC.UConfig(tlsConfig), + TLSClientConfig: tlsConfig, QUICConfig: doh.getQUICConfig(), } return &http3Transport{baseTransport: rt}, nil } -func (doh *dnsOverHTTPS) dialQuic(ctx context.Context, addr string, tlsCfg *tlsC.Config, cfg *quic.Config) (*quic.Conn, error) { +func (doh *dnsOverHTTPS) dialQuic(ctx context.Context, addr string, tlsCfg *tls.Config, cfg *quic.Config) (*quic.Conn, error) { ip, port, err := net.SplitHostPort(addr) if err != nil { return nil, err @@ -612,7 +610,7 @@ func (doh *dnsOverHTTPS) probeH3( // Run probeQUIC and probeTLS in parallel and see which one is faster. chQuic := make(chan error, 1) chTLS := make(chan error, 1) - go doh.probeQUIC(ctx, addr, tlsC.UConfig(probeTLSCfg), chQuic) + go doh.probeQUIC(ctx, addr, probeTLSCfg, chQuic) go doh.probeTLS(ctx, probeTLSCfg, chTLS) select { @@ -637,7 +635,7 @@ func (doh *dnsOverHTTPS) probeH3( // probeQUIC attempts to establish a QUIC connection to the specified address. // We run probeQUIC and probeTLS in parallel and see which one is faster. -func (doh *dnsOverHTTPS) probeQUIC(ctx context.Context, addr string, tlsConfig *tlsC.Config, ch chan error) { +func (doh *dnsOverHTTPS) probeQUIC(ctx context.Context, addr string, tlsConfig *tls.Config, ch chan error) { startTime := time.Now() conn, err := doh.dialQuic(ctx, addr, tlsConfig, doh.getQUICConfig()) if err != nil { diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/doq.go b/clash-meta-android/core/src/foss/golang/clash/dns/doq.go index 6861bd4d11..18459e97db 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/doq.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/doq.go @@ -2,7 +2,6 @@ package dns import ( "context" - "crypto/tls" "encoding/binary" "errors" "fmt" @@ -13,11 +12,11 @@ import ( "time" "github.com/metacubex/mihomo/component/ca" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" "github.com/metacubex/quic-go" + "github.com/metacubex/tls" D "github.com/miekg/dns" ) @@ -348,7 +347,7 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn *quic.Conn, er transport := quic.Transport{Conn: udp} transport.SetCreatedConn(true) // auto close conn transport.SetSingleUse(true) // auto close transport - conn, err = transport.Dial(ctx, &udpAddr, tlsC.UConfig(tlsConfig), doq.getQUICConfig()) + conn, err = transport.Dial(ctx, &udpAddr, tlsConfig, doq.getQUICConfig()) if err != nil { return nil, fmt.Errorf("opening quic connection to %s: %w", doq.addr, err) } diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go b/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go index f7d4d42968..fd51507dfb 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go @@ -165,11 +165,9 @@ func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, e q := m.Question[0] domain := msgToDomain(m) - _, qTypeStr := msgToQtype(m) cacheM, expireTime, hit := r.cache.GetWithExpire(q.String()) if hit { - ips := msgToIP(cacheM) - log.Debugln("[DNS] cache hit %s --> %s %s, expire at %s", domain, ips, qTypeStr, expireTime.Format("2006-01-02 15:04:05")) + log.Debugln("[DNS] cache hit %s --> %s, expire at %s", domain, msgToLogString(cacheM), expireTime.Format("2006-01-02 15:04:05")) now := time.Now() msg = cacheM.Copy() if expireTime.Before(now) { diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/util.go b/clash-meta-android/core/src/foss/golang/clash/dns/util.go index 12dd59b4ab..e960a8e198 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/util.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/util.go @@ -9,6 +9,7 @@ import ( "time" "github.com/metacubex/mihomo/common/picker" + "github.com/metacubex/mihomo/component/ech/echparser" "github.com/metacubex/mihomo/component/resolver" "github.com/metacubex/mihomo/log" @@ -226,6 +227,81 @@ func msgToQtype(msg *D.Msg) (uint16, string) { return 0, "" } +func msgToHTTPSRRInfo(msg *D.Msg) string { + var alpns []string + var publicName string + var hasIPv4, hasIPv6 bool + + collect := func(rrs []D.RR) { + for _, rr := range rrs { + httpsRR, ok := rr.(*D.HTTPS) + if !ok { + continue + } + + for _, kv := range httpsRR.Value { + switch v := kv.(type) { + case *D.SVCBAlpn: + if len(alpns) == 0 && len(v.Alpn) > 0 { + alpns = append(alpns, v.Alpn...) + } + case *D.SVCBIPv4Hint: + if len(v.Hint) > 0 { + hasIPv4 = true + } + case *D.SVCBIPv6Hint: + if len(v.Hint) > 0 { + hasIPv6 = true + } + case *D.SVCBECHConfig: + if publicName == "" && len(v.ECH) > 0 { + if cfgs, err := echparser.ParseECHConfigList(v.ECH); err == nil && len(cfgs) > 0 { + publicName = string(cfgs[0].PublicName) + } + } + } + } + } + } + + collect(msg.Answer) + + //TODO: Do we need to process the data in msg.Extra? + // If so, do we need to validate whether the domain names within it match our request? + // To simplify the problem, let's ignore it for now. + //collect(msg.Extra) + + if len(alpns) == 0 && publicName == "" && !hasIPv4 && !hasIPv6 { + return "" + } + + var parts []string + if len(alpns) > 0 { + parts = append(parts, "alpn:"+strings.Join(alpns, ",")) + } + if publicName != "" { + parts = append(parts, "pn:"+publicName) + } + if hasIPv4 { + parts = append(parts, "ipv4hint") + } + if hasIPv6 { + parts = append(parts, "ipv6hint") + } + + return strings.Join(parts, ";") +} + +func msgToLogString(msg *D.Msg) string { + qType, qTypeStr := msgToQtype(msg) + switch qType { + case D.TypeHTTPS: + return fmt.Sprintf("[%s] %s", msgToHTTPSRRInfo(msg), qTypeStr) + default: + return fmt.Sprintf("%s %s", msgToIP(msg), qTypeStr) + } +} + func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, cache bool, err error) { cache = true fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) @@ -248,8 +324,7 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M // so we would ignore RCode errors from RCode clients. return nil, errors.New("server failure: " + D.RcodeToString[m.Rcode]) } - ips := msgToIP(m) - log.Debugln("[DNS] %s --> %s %s from %s", domain, ips, qTypeStr, client.Address()) + log.Debugln("[DNS] %s --> %s from %s", domain, msgToLogString(m), client.Address()) return m, nil }) } diff --git a/clash-meta-android/core/src/foss/golang/clash/docker/file-name.sh b/clash-meta-android/core/src/foss/golang/clash/docker/file-name.sh index 21cb61efb3..bd09da9572 100644 --- a/clash-meta-android/core/src/foss/golang/clash/docker/file-name.sh +++ b/clash-meta-android/core/src/foss/golang/clash/docker/file-name.sh @@ -13,7 +13,7 @@ case $TARGETPLATFORM in "linux/arm/v7") arch="armv7" ;; - "riscv64") + "linux/riscv64") arch="riscv64" ;; *) @@ -22,4 +22,4 @@ case $TARGETPLATFORM in ;; esac file_name="$os$arch-$(cat bin/version.txt)" -echo $file_name \ No newline at end of file +echo $file_name diff --git a/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml b/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml index bef2c65914..04d15bd202 100644 --- a/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml +++ b/clash-meta-android/core/src/foss/golang/clash/docs/config.yaml @@ -1048,7 +1048,11 @@ proxies: # socks5 padding-min: 2 # 最小填充字节数 padding-max: 7 # 最大填充字节数 table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy 前者全ascii映射,后者保证熵值(汉明1)低于3 + # custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合。启用此处则需配置`table-type`为`prefer_entropy` + # custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),用于 xvp 模式轮换;非空时覆盖 custom-table http-mask: true # 是否启用http掩码 + # http-mask-strategy: random # 可选:random(默认)、post、websocket;仅在 http-mask=true 时生效 + enable-pure-downlink: false # 是否启用混淆下行,false的情况下能在保证数据安全的前提下极大提升下行速度,与服务端端保持相同(如果此处为false,则要求aead不可为none) # anytls - name: anytls @@ -1587,9 +1591,12 @@ listeners: aead-method: chacha20-poly1305 # 支持chacha20-poly1305或者aes-128-gcm以及none,sudoku的混淆层可以确保none情况下数据安全 padding-min: 1 # 填充最小长度 padding-max: 15 # 填充最大长度,均不建议过大 - seed: "" # 如果你不使用ED25519密钥对,就请填入uuid,否则仍然是公钥 table-type: prefer_ascii # 可选值:prefer_ascii、prefer_entropy 前者全ascii映射,后者保证熵值(汉明1)低于3 + # custom-table: xpxvvpvv # 可选,自定义字节布局,必须包含2个x、2个p、4个v,可随意组合。启用此处则需配置`table-type`为`prefer_entropy` + # custom-tables: ["xpxvvpvv", "vxpvxvvp"] # 可选,自定义字节布局列表(x/v/p),用于 xvp 模式轮换;非空时覆盖 custom-table handshake-timeout: 5 # optional + enable-pure-downlink: false # 是否启用混淆下行,false的情况下能在保证数据安全的前提下极大提升下行速度,与客户端保持相同(如果此处为false,则要求aead不可为none) + - name: trojan-in-1 @@ -1740,4 +1747,3 @@ listeners: # alpn: # - h3 # max-udp-relay-packet-size: 1500 - diff --git a/clash-meta-android/core/src/foss/golang/clash/go.mod b/clash-meta-android/core/src/foss/golang/clash/go.mod index 35dfcbe2b1..e15afab758 100644 --- a/clash-meta-android/core/src/foss/golang/clash/go.mod +++ b/clash-meta-android/core/src/foss/golang/clash/go.mod @@ -7,8 +7,6 @@ require ( github.com/coreos/go-iptables v0.8.0 github.com/dlclark/regexp2 v1.11.5 github.com/enfein/mieru/v3 v3.26.0 - github.com/go-chi/chi/v5 v5.2.3 - github.com/go-chi/render v1.0.3 github.com/gobwas/ws v1.4.0 github.com/gofrs/uuid/v5 v5.4.0 github.com/golang/snappy v1.0.0 @@ -20,31 +18,35 @@ require ( github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b github.com/metacubex/blake3 v0.1.0 github.com/metacubex/chacha v0.1.5 + github.com/metacubex/chi v0.1.0 + github.com/metacubex/cpu v0.1.0 github.com/metacubex/fswatch v0.1.1 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 + github.com/metacubex/http v0.1.0 github.com/metacubex/kcp-go v0.0.0-20251111012849-7455698490e9 - github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128 + github.com/metacubex/mlkem v0.1.0 + github.com/metacubex/quic-go v0.57.1-0.20251217071004-e89f497a2e72 github.com/metacubex/randv2 v0.2.0 github.com/metacubex/restls-client-go v0.1.7 github.com/metacubex/sing v0.5.6 github.com/metacubex/sing-mux v0.3.4 - github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb + github.com/metacubex/sing-quic v0.0.0-20251217080445-b15217cb57f3 github.com/metacubex/sing-shadowsocks v0.2.12 github.com/metacubex/sing-shadowsocks2 v0.2.7 github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 - github.com/metacubex/sing-tun v0.4.10 + github.com/metacubex/sing-tun v0.4.11 github.com/metacubex/sing-vmess v0.2.4 github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1 github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 + github.com/metacubex/tls v0.1.0 github.com/metacubex/utls v1.8.3 github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f github.com/miekg/dns v1.1.63 // lastest version compatible with golang1.20 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 // lastest version compatible with golang1.20 - github.com/saba-futai/sudoku v0.0.1-g - github.com/sagernet/cors v1.2.1 + github.com/saba-futai/sudoku v0.0.2-d github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a github.com/samber/lo v1.52.0 github.com/sirupsen/logrus v1.9.3 @@ -78,12 +80,11 @@ require ( github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect + github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/reedsolomon v1.12.3 // indirect @@ -92,13 +93,14 @@ require ( github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/ascon v0.1.0 // indirect github.com/metacubex/gvisor v0.0.0-20250919004547-6122b699a301 // indirect + github.com/metacubex/hkdf v0.1.0 // indirect + github.com/metacubex/hpke v0.1.0 // indirect github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect + github.com/metacubex/qpack v0.6.0 // indirect github.com/metacubex/yamux v0.0.0-20250918083631-dd5f17c0be49 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect - github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/quic-go/qpack v0.4.0 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect @@ -108,6 +110,6 @@ require ( gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect golang.org/x/mod v0.20.0 // indirect golang.org/x/text v0.22.0 // indirect - golang.org/x/time v0.7.0 // indirect + golang.org/x/time v0.10.0 // indirect golang.org/x/tools v0.24.0 // indirect ) diff --git a/clash-meta-android/core/src/foss/golang/clash/go.sum b/clash-meta-android/core/src/foss/golang/clash/go.sum index 45210afb98..2a01c51737 100644 --- a/clash-meta-android/core/src/foss/golang/clash/go.sum +++ b/clash-meta-android/core/src/foss/golang/clash/go.sum @@ -14,9 +14,6 @@ github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xW github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc= github.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -40,15 +37,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= -github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= -github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= -github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= -github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= @@ -58,17 +48,15 @@ github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakr github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0= github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4= github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -102,18 +90,32 @@ github.com/metacubex/blake3 v0.1.0 h1:KGnjh/56REO7U+cgZA8dnBhxdP7jByrG7hTP+bu6cq github.com/metacubex/blake3 v0.1.0/go.mod h1:CCkLdzFrqf7xmxCdhQFvJsRRV2mwOLDoSPg6vUTB9Uk= github.com/metacubex/chacha v0.1.5 h1:fKWMb/5c7ZrY8Uoqi79PPFxl+qwR7X/q0OrsAubyX2M= github.com/metacubex/chacha v0.1.5/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8= +github.com/metacubex/chi v0.1.0 h1:rjNDyDj50nRpicG43CNkIw4ssiCbmDL8d7wJXKlUCsg= +github.com/metacubex/chi v0.1.0/go.mod h1:zM5u5oMQt8b2DjvDHvzadKrP6B2ztmasL1YHRMbVV+g= +github.com/metacubex/cpu v0.1.0 h1:8PeTdV9j6UKbN1K5Jvtbi/Jock7dknvzyYuLb8Conmk= +github.com/metacubex/cpu v0.1.0/go.mod h1:09VEt4dSRLR+bOA8l4w4NDuzGZ8n5dkMv7e8axgEeTU= github.com/metacubex/fswatch v0.1.1 h1:jqU7C/v+g0qc2RUFgmAOPoVvfl2BXXUXEumn6oQuxhU= github.com/metacubex/fswatch v0.1.1/go.mod h1:czrTT7Zlbz7vWft8RQu9Qqh+JoX+Nnb+UabuyN1YsgI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20250919004547-6122b699a301 h1:N5GExQJqYAH3gOCshpp2u/J3CtNYzMctmlb0xK9wtbQ= github.com/metacubex/gvisor v0.0.0-20250919004547-6122b699a301/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU= +github.com/metacubex/hkdf v0.1.0 h1:fPA6VzXK8cU1foc/TOmGCDmSa7pZbxlnqhl3RNsthaA= +github.com/metacubex/hkdf v0.1.0/go.mod h1:3seEfds3smgTAXqUGn+tgEJH3uXdsUjOiduG/2EtvZ4= +github.com/metacubex/hpke v0.1.0 h1:gu2jUNhraehWi0P/z5HX2md3d7L1FhPQE6/Q0E9r9xQ= +github.com/metacubex/hpke v0.1.0/go.mod h1:vfDm6gfgrwlXUxKDkWbcE44hXtmc1uxLDm2BcR11b3U= +github.com/metacubex/http v0.1.0 h1:Jcy0I9zKjYijSUaksZU34XEe2xNdoFkgUTB7z7K5q0o= +github.com/metacubex/http v0.1.0/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg= github.com/metacubex/kcp-go v0.0.0-20251111012849-7455698490e9 h1:7m3tRPrLpKOLOvZ/Lp4XCxz0t7rg9t9K35x6TahjR8o= github.com/metacubex/kcp-go v0.0.0-20251111012849-7455698490e9/go.mod h1:HIJZW4QMhbBqXuqC1ly6Hn0TEYT2SzRw58ns1yGhXTs= +github.com/metacubex/mlkem v0.1.0 h1:wFClitonSFcmipzzQvax75beLQU+D7JuC+VK1RzSL8I= +github.com/metacubex/mlkem v0.1.0/go.mod h1:amhaXZVeYNShuy9BILcR7P0gbeo/QLZsnqCdL8U2PDQ= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA= -github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128 h1:I1uvJl206/HbkzEAZpLgGkZgUveOZb+P+6oTUj7dN+o= -github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c= +github.com/metacubex/qpack v0.6.0 h1:YqClGIMOpiRYLjV1qOs483Od08MdPgRnHjt90FuaAKw= +github.com/metacubex/qpack v0.6.0/go.mod h1:lKGSi7Xk94IMvHGOmxS9eIei3bvIqpOAImEBsaOwTkA= +github.com/metacubex/quic-go v0.57.1-0.20251217071004-e89f497a2e72 h1:kNlYHZ75itJwkerDiySpixX+dKsv/K0TYQsKvuxogNM= +github.com/metacubex/quic-go v0.57.1-0.20251217071004-e89f497a2e72/go.mod h1:N071X2oW2+kIhLlHW3mfcD2QP+zWu2bEs1EEAm66bvI= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k= @@ -123,16 +125,16 @@ github.com/metacubex/sing v0.5.6 h1:mEPDCadsCj3DB8gn+t/EtposlYuALEkExa/LUguw6/c= github.com/metacubex/sing v0.5.6/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w= github.com/metacubex/sing-mux v0.3.4 h1:tf4r27CIkzaxq9kBlAXQkgMXq2HPp5Mta60Kb4RCZF0= github.com/metacubex/sing-mux v0.3.4/go.mod h1:SEJfAuykNj/ozbPqngEYqyggwSr81+L7Nu09NRD5mh4= -github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb h1:gxrJmnxuEAel+kh3V7ntqkHjURif0xKDu76nzr/BF5Y= -github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb/go.mod h1:JK4+PYUKps6pnlicKjsSUAjAcvIUjhorIjdNZGg930M= +github.com/metacubex/sing-quic v0.0.0-20251217080445-b15217cb57f3 h1:3LlkguIRAzyBWLxP5xrETi1AMIt3McZcDlXNgiyXMsE= +github.com/metacubex/sing-quic v0.0.0-20251217080445-b15217cb57f3/go.mod h1:fAyoc/8IFK1yJp8meJvPNyGk7ZnKG1vmNaTwYx6NHA4= github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE= github.com/metacubex/sing-shadowsocks v0.2.12/go.mod h1:2e5EIaw0rxKrm1YTRmiMnDulwbGxH9hAFlrwQLQMQkU= github.com/metacubex/sing-shadowsocks2 v0.2.7 h1:hSuuc0YpsfiqYqt1o+fP4m34BQz4e6wVj3PPBVhor3A= github.com/metacubex/sing-shadowsocks2 v0.2.7/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE= github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI= github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E= -github.com/metacubex/sing-tun v0.4.10 h1:DllQTERAcqQyiEl4L/R7Ia0jCiSzZzikw2kL8N85p0E= -github.com/metacubex/sing-tun v0.4.10/go.mod h1:L/TjQY5JEGy8nvsuYmy/XgMFMCPiF0+AWSFCYfS6r9w= +github.com/metacubex/sing-tun v0.4.11 h1:NG5zpvYPbBXf+9GSUmDaGCDwl3hZXV677tbRAw0QtCM= +github.com/metacubex/sing-tun v0.4.11/go.mod h1:L/TjQY5JEGy8nvsuYmy/XgMFMCPiF0+AWSFCYfS6r9w= github.com/metacubex/sing-vmess v0.2.4 h1:Tx6AGgCiEf400E/xyDuYyafsel6sGbR8oF7RkAaus6I= github.com/metacubex/sing-vmess v0.2.4/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM= github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU= @@ -141,6 +143,8 @@ github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1 h1:a6DF0ze9miXes+rd github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE= github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 h1:H6TnfM12tOoTizYE/qBHH3nEuibIelmHI+BVSxVJr8o= github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= +github.com/metacubex/tls v0.1.0 h1:1kjR/1q2uU1cZIwiHYEnWzS4L+0Cu1/X3yfIQ76BzNY= +github.com/metacubex/tls v0.1.0/go.mod h1:0XeVdL0cBw+8i5Hqy3lVeP9IyD/LFTq02ExvHM6rzEM= github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4= github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk= @@ -153,9 +157,6 @@ github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0= github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= @@ -169,12 +170,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= -github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/saba-futai/sudoku v0.0.1-g h1:4q6OuAA6COaRW+CgoQtdim5AUPzzm0uOkvbYpJnOaBE= -github.com/saba-futai/sudoku v0.0.1-g/go.mod h1:2ZRzRwz93cS2K/o2yOG4CPJEltcvk5y6vbvUmjftGU0= -github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= -github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= +github.com/saba-futai/sudoku v0.0.2-d h1:HW/gIyNUFcDchpMN+ZhluM86U/HGkWkkRV+9Km6WZM8= +github.com/saba-futai/sudoku v0.0.2-d/go.mod h1:Rvggsoprp7HQM7bMIZUd1M27bPj8THRsZdY1dGbIAvo= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= @@ -244,7 +241,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -258,8 +254,8 @@ golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/cache.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/cache.go index 78bda737be..f2eda53a87 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/cache.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/cache.go @@ -1,12 +1,11 @@ package route import ( - "net/http" - "github.com/metacubex/mihomo/component/resolver" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" ) func cacheRouter() http.Handler { diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/common.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/common.go index d0053e674b..a0b9261da8 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/common.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/common.go @@ -1,10 +1,20 @@ package route import ( - "net/http" + "bufio" + "encoding/binary" + "errors" + "io" + "net" "net/url" + "strconv" + "strings" + "time" - "github.com/go-chi/chi/v5" + N "github.com/metacubex/mihomo/common/net" + + "github.com/metacubex/chi" + "github.com/metacubex/http" ) // When name is composed of a partial escape string, Golang does not unescape it @@ -15,3 +25,151 @@ func getEscapeParam(r *http.Request, paramName string) string { } return param } + +// wsUpgrade upgrades http connection to the websocket connection. +// +// It hijacks net.Conn from w and returns received net.Conn and +// bufio.ReadWriter. +func wsUpgrade(r *http.Request, w http.ResponseWriter) (conn net.Conn, rw *bufio.ReadWriter, err error) { + // See https://tools.ietf.org/html/rfc6455#section-4.1 + // The method of the request MUST be GET, and the HTTP version MUST be at least 1.1. + var nonce string + if r.Method != http.MethodGet { + err = errors.New("handshake error: bad HTTP request method") + body := err.Error() + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.WriteHeader(http.StatusMethodNotAllowed) + w.Write([]byte(body)) + return nil, nil, err + } else if r.ProtoMajor < 1 || (r.ProtoMajor == 1 && r.ProtoMinor < 1) { + err = errors.New("handshake error: bad HTTP protocol version") + body := err.Error() + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.WriteHeader(http.StatusHTTPVersionNotSupported) + w.Write([]byte(body)) + return nil, nil, err + } else if r.Host == "" { + err = errors.New("handshake error: bad Host header") + body := err.Error() + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(body)) + return nil, nil, err + } else if u := r.Header.Get("Upgrade"); u != "websocket" && !strings.EqualFold(u, "websocket") { + err = errors.New("handshake error: bad Upgrade header") + body := err.Error() + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(body)) + return nil, nil, err + } else if c := r.Header.Get("Connection"); c != "Upgrade" && !strings.Contains(strings.ToLower(c), "upgrade") { + err = errors.New("handshake error: bad Connection header") + body := err.Error() + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(body)) + return nil, nil, err + } else if nonce = r.Header.Get("Sec-WebSocket-Key"); len(nonce) != 24 { + err = errors.New("handshake error: bad Sec-WebSocket-Key header") + body := err.Error() + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(body)) + return nil, nil, err + } else if v := r.Header.Get("Sec-WebSocket-Version"); v != "13" { + err = errors.New("handshake error: bad Sec-WebSocket-Version header") + body := err.Error() + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + if v != "" { + // According to RFC6455: + // If this version does not match a version understood by the server, the + // server MUST abort the WebSocket handshake described in this section and + // instead send an appropriate HTTP error code (such as 426 Upgrade Required) + // and a |Sec-WebSocket-Version| header field indicating the version(s) the + // server is capable of understanding. + w.Header().Set("Sec-WebSocket-Version", "13") + w.WriteHeader(http.StatusUpgradeRequired) + } else { + w.WriteHeader(http.StatusBadRequest) + } + w.Write([]byte(body)) + return nil, nil, err + } + + conn, rw, err = http.NewResponseController(w).Hijack() + if err != nil { + body := err.Error() + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("Content-Length", strconv.Itoa(len(body))) + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(body)) + return nil, nil, err + } + + // Clear deadlines set by server. + conn.SetDeadline(time.Time{}) + + rw.Writer.WriteString("HTTP/1.1 101 Switching Protocols\r\n") + header := http.Header{} + header.Set("Upgrade", "websocket") + header.Set("Connection", "Upgrade") + header.Set("Sec-WebSocket-Accept", N.GetWebSocketSecAccept(nonce)) + header.Write(rw.Writer) + rw.Writer.WriteString("\r\n") + err = rw.Writer.Flush() + + return conn, rw, err +} + +// wsWriteServerMessage writes message to w, considering that caller represents server side. +func wsWriteServerMessage(w io.Writer, op byte, p []byte) error { + dataLen := len(p) + + // Make slice of bytes with capacity 14 that could hold any header. + bts := make([]byte, 14) + + bts[0] |= 0x80 //FIN + bts[0] |= 0 << 4 //RSV + bts[0] |= op //OPCODE + + var n int + switch { + case dataLen < 126: + bts[1] = byte(dataLen) + n = 2 + case dataLen < 65536: + bts[1] = 126 + binary.BigEndian.PutUint16(bts[2:4], uint16(dataLen)) + n = 4 + default: + bts[1] = 127 + binary.BigEndian.PutUint64(bts[2:10], uint64(dataLen)) + n = 10 + } + + _, err := w.Write(bts[:n]) + if err != nil { + return err + } + _, err = w.Write(p) + return err +} + +// wsWriteServerText is the same as wsWriteServerMessage with ws.OpText. +func wsWriteServerText(w io.Writer, p []byte) error { + const opText = 0x1 + return wsWriteServerMessage(w, opText, p) +} + +// wsWriteServerBinary is the same as wsWriteServerMessage with ws.OpBinary. +func wsWriteServerBinary(w io.Writer, p []byte) error { + const opBinary = 0x2 + return wsWriteServerMessage(w, opBinary, p) +} diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/configs.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/configs.go index 141a6c1559..af33074330 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/configs.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/configs.go @@ -1,7 +1,6 @@ package route import ( - "net/http" "net/netip" "path/filepath" @@ -18,8 +17,9 @@ import ( "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/tunnel" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" ) func configRouter() http.Handler { diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/connections.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/connections.go index e0ff242648..ddfa6c58f8 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/connections.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/connections.go @@ -3,16 +3,14 @@ package route import ( "bytes" "encoding/json" - "net/http" "strconv" "time" "github.com/metacubex/mihomo/tunnel/statistic" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" ) func connectionRouter() http.Handler { @@ -30,7 +28,7 @@ func getConnections(w http.ResponseWriter, r *http.Request) { return } - conn, _, _, err := ws.UpgradeHTTP(r, w) + conn, _, err := wsUpgrade(r, w) if err != nil { return } @@ -56,7 +54,7 @@ func getConnections(w http.ResponseWriter, r *http.Request) { return err } - return wsutil.WriteMessage(conn, ws.StateServerSide, ws.OpText, buf.Bytes()) + return wsWriteServerText(conn, buf.Bytes()) } if err := sendSnapshot(); err != nil { diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/dns.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/dns.go index 1762c94719..5a805a180a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/dns.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/dns.go @@ -3,12 +3,12 @@ package route import ( "context" "math" - "net/http" "github.com/metacubex/mihomo/component/resolver" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" "github.com/miekg/dns" "github.com/samber/lo" ) diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/doh.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/doh.go index bb5416c436..3e0c30cff3 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/doh.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/doh.go @@ -4,11 +4,11 @@ import ( "context" "encoding/base64" "io" - "net/http" "github.com/metacubex/mihomo/component/resolver" - "github.com/go-chi/render" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" ) func dohRouter() http.Handler { diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/external.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/external.go index d2f0635822..2b1ce6a06c 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/external.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/external.go @@ -1,6 +1,6 @@ package route -import "github.com/go-chi/chi/v5" +import "github.com/metacubex/chi" type externalRouter func(r chi.Router) diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/groups.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/groups.go index 873a94df51..5d5e5b817f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/groups.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/groups.go @@ -2,18 +2,18 @@ package route import ( "context" - "net/http" "strconv" "time" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" - "github.com/metacubex/mihomo/adapter/outboundgroup" "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/profile/cachefile" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/tunnel" + + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" ) func groupRouter() http.Handler { @@ -31,7 +31,7 @@ func groupRouter() http.Handler { func getGroups(w http.ResponseWriter, r *http.Request) { var gs []C.Proxy for _, p := range tunnel.Proxies() { - if _, ok := p.Adapter().(C.Group); ok { + if _, ok := p.Adapter().(outboundgroup.ProxyGroup); ok { gs = append(gs, p) } } @@ -42,7 +42,7 @@ func getGroups(w http.ResponseWriter, r *http.Request) { func getGroup(w http.ResponseWriter, r *http.Request) { proxy := r.Context().Value(CtxKeyProxy).(C.Proxy) - if _, ok := proxy.Adapter().(C.Group); ok { + if _, ok := proxy.Adapter().(outboundgroup.ProxyGroup); ok { render.JSON(w, r, proxy) return } @@ -52,7 +52,7 @@ func getGroup(w http.ResponseWriter, r *http.Request) { func getGroupDelay(w http.ResponseWriter, r *http.Request) { proxy := r.Context().Value(CtxKeyProxy).(C.Proxy) - group, ok := proxy.Adapter().(C.Group) + group, ok := proxy.Adapter().(outboundgroup.ProxyGroup) if !ok { render.Status(r, http.StatusNotFound) render.JSON(w, r, ErrNotFound) diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/provider.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/provider.go index 24b1989ed1..c060cc895d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/provider.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/provider.go @@ -2,14 +2,14 @@ package route import ( "context" - "net/http" C "github.com/metacubex/mihomo/constant" P "github.com/metacubex/mihomo/constant/provider" "github.com/metacubex/mihomo/tunnel" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" "github.com/samber/lo" ) diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/proxies.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/proxies.go index ba4e03f902..f100adbb7d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/proxies.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/proxies.go @@ -3,7 +3,6 @@ package route import ( "context" "fmt" - "net/http" "strconv" "time" @@ -13,8 +12,9 @@ import ( C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/tunnel" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" ) var ( diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/restart.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/restart.go index 49d7e51703..89a95be940 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/restart.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/restart.go @@ -2,7 +2,6 @@ package route import ( "fmt" - "net/http" "os" "os/exec" "runtime" @@ -11,8 +10,9 @@ import ( "github.com/metacubex/mihomo/hub/executor" "github.com/metacubex/mihomo/log" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" ) func restartRouter() http.Handler { diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/rules.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/rules.go index 43d33299a2..e2d4d82ab4 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/rules.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/rules.go @@ -2,12 +2,11 @@ package route import ( "github.com/metacubex/mihomo/constant" - "net/http" - "github.com/metacubex/mihomo/tunnel" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" ) func ruleRouter() http.Handler { diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/server.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/server.go index f2a52d4208..4e0d0c93f5 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/server.go @@ -5,7 +5,6 @@ import ( "crypto/subtle" "encoding/json" "net" - "net/http" "os" "path/filepath" "runtime/debug" @@ -17,18 +16,17 @@ import ( "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/ntp" "github.com/metacubex/mihomo/tunnel/statistic" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" - "github.com/go-chi/render" - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/sagernet/cors" + "github.com/metacubex/chi" + "github.com/metacubex/chi/cors" + "github.com/metacubex/chi/middleware" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" + "github.com/metacubex/tls" ) var ( @@ -47,8 +45,10 @@ func SetEmbedMode(embed bool) { } type Traffic struct { - Up int64 `json:"up"` - Down int64 `json:"down"` + Up int64 `json:"up"` + Down int64 `json:"down"` + UpTotal int64 `json:"upTotal"` + DownTotal int64 `json:"downTotal"` } type Memory struct { @@ -191,7 +191,7 @@ func startTLS(cfg *Config) { // handle tlsAddr if len(cfg.TLSAddr) > 0 { - cert, err := ca.LoadTLSKeyPair(cfg.Certificate, cfg.PrivateKey, C.Path) + certLoader, err := ca.NewTLSKeyPairLoader(cfg.Certificate, cfg.PrivateKey) if err != nil { log.Errorln("External controller tls listen error: %s", err) return @@ -204,17 +204,19 @@ func startTLS(cfg *Config) { } log.Infoln("RESTful API tls listening at: %s", l.Addr().String()) - tlsConfig := &tlsC.Config{Time: ntp.Now} + tlsConfig := &tls.Config{Time: ntp.Now} tlsConfig.NextProtos = []string{"h2", "http/1.1"} - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(cfg.ClientAuthType) + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() + } + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(cfg.ClientAuthType) if len(cfg.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(cfg.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(cfg.ClientAuthCert) if err != nil { log.Errorln("External controller tls listen error: %s", err) return @@ -223,7 +225,7 @@ func startTLS(cfg *Config) { } if cfg.EchKey != "" { - err = ech.LoadECHKey(cfg.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(cfg.EchKey, tlsConfig) if err != nil { log.Errorln("External controller tls serve error: %s", err) return @@ -233,7 +235,7 @@ func startTLS(cfg *Config) { Handler: router(cfg.IsDebug, cfg.Secret, cfg.DohServer, cfg.Cors), } tlsServer = server - if err = server.Serve(tlsC.NewListenerForHttps(l, server, tlsConfig)); err != nil { + if err = server.Serve(tls.NewListener(l, tlsConfig)); err != nil { log.Errorln("External controller tls serve error: %s", err) } } @@ -361,7 +363,7 @@ func traffic(w http.ResponseWriter, r *http.Request) { var wsConn net.Conn if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, _, _, err = ws.UpgradeHTTP(r, w) + wsConn, _, err = wsUpgrade(r, w) if err != nil { return } @@ -380,9 +382,12 @@ func traffic(w http.ResponseWriter, r *http.Request) { for range tick.C { buf.Reset() up, down := t.Now() + upTotal, downTotal := t.Total() if err := json.NewEncoder(buf).Encode(Traffic{ - Up: up, - Down: down, + Up: up, + Down: down, + UpTotal: upTotal, + DownTotal: downTotal, }); err != nil { break } @@ -391,7 +396,7 @@ func traffic(w http.ResponseWriter, r *http.Request) { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsutil.WriteMessage(wsConn, ws.StateServerSide, ws.OpText, buf.Bytes()) + err = wsWriteServerText(wsConn, buf.Bytes()) } if err != nil { @@ -404,7 +409,7 @@ func memory(w http.ResponseWriter, r *http.Request) { var wsConn net.Conn if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, _, _, err = ws.UpgradeHTTP(r, w) + wsConn, _, err = wsUpgrade(r, w) if err != nil { return } @@ -441,7 +446,7 @@ func memory(w http.ResponseWriter, r *http.Request) { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsutil.WriteMessage(wsConn, ws.StateServerSide, ws.OpText, buf.Bytes()) + err = wsWriteServerText(wsConn, buf.Bytes()) } if err != nil { @@ -487,7 +492,7 @@ func getLogs(w http.ResponseWriter, r *http.Request) { var wsConn net.Conn if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, _, _, err = ws.UpgradeHTTP(r, w) + wsConn, _, err = wsUpgrade(r, w) if err != nil { return } @@ -546,7 +551,7 @@ func getLogs(w http.ResponseWriter, r *http.Request) { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsutil.WriteMessage(wsConn, ws.StateServerSide, ws.OpText, buf.Bytes()) + err = wsWriteServerText(wsConn, buf.Bytes()) } if err != nil { diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/route/upgrade.go b/clash-meta-android/core/src/foss/golang/clash/hub/route/upgrade.go index b2bcecd20a..b3593669a0 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/route/upgrade.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/route/upgrade.go @@ -2,14 +2,14 @@ package route import ( "fmt" - "net/http" "os" "github.com/metacubex/mihomo/component/updater" "github.com/metacubex/mihomo/log" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" ) func upgradeRouter() http.Handler { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/anytls/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/anytls/server.go index 99f1d7bb56..0d35d4d6af 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/anytls/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/anytls/server.go @@ -13,7 +13,6 @@ import ( "github.com/metacubex/mihomo/common/buf" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing" @@ -24,13 +23,14 @@ import ( "github.com/metacubex/sing/common/auth" "github.com/metacubex/sing/common/bufio" M "github.com/metacubex/sing/common/metadata" + "github.com/metacubex/tls" ) type Listener struct { closed bool config LC.AnyTLSServer listeners []net.Listener - tlsConfig *tlsC.Config + tlsConfig *tls.Config userMap map[[32]byte]string padding atomic.Pointer[padding.PaddingFactory] } @@ -43,29 +43,31 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition) } } - tlsConfig := &tlsC.Config{Time: ntp.Now} + tlsConfig := &tls.Config{Time: ntp.Now} if config.Certificate != "" && config.PrivateKey != "" { - cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) + certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey) if err != nil { return nil, err } - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() + } if config.EchKey != "" { - err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(config.EchKey, tlsConfig) if err != nil { return nil, err } } } - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType) + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType) if len(config.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(config.ClientAuthCert) if err != nil { return nil, err } @@ -108,8 +110,8 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition) if err != nil { return nil, err } - if len(tlsConfig.Certificates) > 0 { - l = tlsC.NewListener(l, tlsConfig) + if tlsConfig.GetCertificate != nil { + l = tls.NewListener(l, tlsConfig) } else { return nil, errors.New("disallow using AnyTLS without certificates config") } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/config/sudoku.go b/clash-meta-android/core/src/foss/golang/clash/listener/config/sudoku.go index 855795f1c3..848db875d7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/config/sudoku.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/config/sudoku.go @@ -1,19 +1,28 @@ package config -import "encoding/json" +import ( + "encoding/json" + + "github.com/metacubex/mihomo/listener/sing" +) // SudokuServer describes a Sudoku inbound server configuration. // It is internal to the listener layer and mainly used for logging and wiring. type SudokuServer struct { - Enable bool `json:"enable"` - Listen string `json:"listen"` - Key string `json:"key"` - AEADMethod string `json:"aead-method,omitempty"` - PaddingMin *int `json:"padding-min,omitempty"` - PaddingMax *int `json:"padding-max,omitempty"` - Seed string `json:"seed,omitempty"` - TableType string `json:"table-type,omitempty"` - HandshakeTimeoutSecond *int `json:"handshake-timeout,omitempty"` + Enable bool `json:"enable"` + Listen string `json:"listen"` + Key string `json:"key"` + AEADMethod string `json:"aead-method,omitempty"` + PaddingMin *int `json:"padding-min,omitempty"` + PaddingMax *int `json:"padding-max,omitempty"` + TableType string `json:"table-type,omitempty"` + HandshakeTimeoutSecond *int `json:"handshake-timeout,omitempty"` + EnablePureDownlink *bool `json:"enable-pure-downlink,omitempty"` + CustomTable string `json:"custom-table,omitempty"` + CustomTables []string `json:"custom-tables,omitempty"` + + // mihomo private extension (not the part of standard Sudoku protocol) + MuxOption sing.MuxOption `json:"mux-option,omitempty"` } func (s SudokuServer) String() string { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/http/client.go b/clash-meta-android/core/src/foss/golang/clash/listener/http/client.go index 0f084fca7b..9f5c37f8bd 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/http/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/http/client.go @@ -4,13 +4,14 @@ import ( "context" "errors" "net" - "net/http" "time" "github.com/metacubex/mihomo/adapter/inbound" N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/socks5" + + "github.com/metacubex/http" ) func newClient(srcConn net.Conn, tunnel C.Tunnel, additions []inbound.Addition) *http.Client { // additions using slice let caller can change its value (without size) after newClient return diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/http/hack.go b/clash-meta-android/core/src/foss/golang/clash/listener/http/hack.go index c33eb6f1bc..ea54241ea6 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/http/hack.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/http/hack.go @@ -2,9 +2,10 @@ package http import ( "bufio" - "net/http" _ "unsafe" + + "github.com/metacubex/http" ) -//go:linkname ReadRequest net/http.readRequest +//go:linkname ReadRequest github.com/metacubex/http.readRequest func ReadRequest(b *bufio.Reader) (req *http.Request, err error) diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/http/proxy.go b/clash-meta-android/core/src/foss/golang/clash/listener/http/proxy.go index 5c08cd458a..588d0f6df5 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/http/proxy.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/http/proxy.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "net" - "net/http" "strings" "sync" @@ -14,6 +13,8 @@ import ( "github.com/metacubex/mihomo/component/auth" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" + + "github.com/metacubex/http" ) type bodyWrapper struct { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/http/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/http/server.go index 8b86ac6213..2c537dedd0 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/http/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/http/server.go @@ -7,12 +7,13 @@ import ( "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" authStore "github.com/metacubex/mihomo/listener/auth" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/reality" "github.com/metacubex/mihomo/ntp" + + "github.com/metacubex/tls" ) type Listener struct { @@ -66,41 +67,43 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A return nil, err } - tlsConfig := &tlsC.Config{Time: ntp.Now} + tlsConfig := &tls.Config{Time: ntp.Now} var realityBuilder *reality.Builder if config.Certificate != "" && config.PrivateKey != "" { - cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) + certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey) if err != nil { return nil, err } - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() + } if config.EchKey != "" { - err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(config.EchKey, tlsConfig) if err != nil { return nil, err } } } - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType) + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType) if len(config.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(config.ClientAuthCert) if err != nil { return nil, err } tlsConfig.ClientCAs = pool } if config.RealityConfig.PrivateKey != "" { - if tlsConfig.Certificates != nil { + if tlsConfig.GetCertificate != nil { return nil, errors.New("certificate is unavailable in reality") } - if tlsConfig.ClientAuth != tlsC.NoClientCert { + if tlsConfig.ClientAuth != tls.NoClientCert { return nil, errors.New("client-auth is unavailable in reality") } realityBuilder, err = config.RealityConfig.Build(tunnel) @@ -111,8 +114,8 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A if realityBuilder != nil { l = realityBuilder.NewListener(l) - } else if len(tlsConfig.Certificates) > 0 { - l = tlsC.NewListener(l, tlsConfig) + } else if tlsConfig.GetCertificate != nil { + l = tls.NewListener(l, tlsConfig) } hl := &Listener{ diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/http/upgrade.go b/clash-meta-android/core/src/foss/golang/clash/listener/http/upgrade.go index ac67ef6889..b658917925 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/http/upgrade.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/http/upgrade.go @@ -2,15 +2,16 @@ package http import ( "context" - "crypto/tls" "net" - "net/http" "strings" "github.com/metacubex/mihomo/adapter/inbound" N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/socks5" + + "github.com/metacubex/http" + "github.com/metacubex/tls" ) func isUpgradeRequest(req *http.Request) bool { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/http/utils.go b/clash-meta-android/core/src/foss/golang/clash/listener/http/utils.go index eb19283da2..4651ce5cda 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/http/utils.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/http/utils.go @@ -4,9 +4,10 @@ import ( "encoding/base64" "errors" "net" - "net/http" "net/netip" "strings" + + "github.com/metacubex/http" ) // removeHopByHopHeaders remove Proxy-* headers diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/common_test.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/common_test.go index 4178035b27..b1be5e4d57 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/common_test.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/common_test.go @@ -4,12 +4,10 @@ import ( "bytes" "context" "crypto/rand" - "crypto/tls" "encoding/base64" "fmt" "io" "net" - "net/http" "net/netip" "strconv" "sync" @@ -23,13 +21,13 @@ import ( "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/ech" "github.com/metacubex/mihomo/component/generator" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" + "github.com/metacubex/chi" + "github.com/metacubex/chi/render" + "github.com/metacubex/http" + "github.com/metacubex/tls" "github.com/stretchr/testify/assert" - "golang.org/x/net/http2" ) var httpPath = "/inbound_test" @@ -157,9 +155,9 @@ func NewHttpTestTunnel() *TestTunnel { io.Copy(io.Discard, r.Body) render.Data(w, r, httpData[:size]) }) - h2Server := &http2.Server{} + //h2Server := &http.Http2Server{} server := http.Server{Handler: r} - _ = http2.ConfigureServer(&server, h2Server) + //_ = http.Http2ConfigureServer(&server, h2Server) go server.Serve(ln) testFn := func(t *testing.T, proxy C.ProxyAdapter, proto string, size int) { req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s://%s%s?size=%d", proto, remoteAddr, httpPath, size), bytes.NewReader(httpData[:size])) @@ -216,6 +214,9 @@ func NewHttpTestTunnel() *TestTunnel { defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) + if proto == "https" { // ensure server using http2 + assert.Equal(t, 2, resp.ProtoMajor) + } data, err := io.ReadAll(resp.Body) if !assert.NoError(t, err) { @@ -268,7 +269,7 @@ func NewHttpTestTunnel() *TestTunnel { ch: make(chan struct{}), } if metadata.DstPort == 443 { - tlsConn := tlsC.Server(c, tlsC.UConfig(tlsConfig)) + tlsConn := tls.Server(c, tlsConfig) if metadata.Host == realityDest { // ignore the tls handshake error for realityDest if realityRealDial { rconn, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress()) @@ -284,11 +285,12 @@ func NewHttpTestTunnel() *TestTunnel { if err := tlsConn.HandshakeContext(ctx); err != nil { return } - if tlsConn.ConnectionState().NegotiatedProtocol == http2.NextProtoTLS { - h2Server.ServeConn(tlsConn, &http2.ServeConnOpts{BaseConfig: &server}) - } else { - ln.ch <- tlsConn - } + //if tlsConn.ConnectionState().NegotiatedProtocol == http.Http2NextProtoTLS { + // h2Server.ServeConn(tlsConn, &http.Http2ServeConnOpts{BaseConfig: &server}) + //} else { + // ln.ch <- tlsConn + //} + ln.ch <- tlsConn } else { ln.ch <- c } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku.go index d6e84af322..433976026d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku.go @@ -5,23 +5,26 @@ import ( "fmt" "strings" - "github.com/saba-futai/sudoku/apis" - C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" - sudokuListener "github.com/metacubex/mihomo/listener/sudoku" + "github.com/metacubex/mihomo/listener/sudoku" "github.com/metacubex/mihomo/log" ) type SudokuOption struct { BaseOption - Key string `inbound:"key"` - AEADMethod string `inbound:"aead-method,omitempty"` - PaddingMin *int `inbound:"padding-min,omitempty"` - PaddingMax *int `inbound:"padding-max,omitempty"` - Seed string `inbound:"seed,omitempty"` - TableType string `inbound:"table-type,omitempty"` // "prefer_ascii" or "prefer_entropy" - HandshakeTimeoutSecond *int `inbound:"handshake-timeout,omitempty"` + Key string `inbound:"key"` + AEADMethod string `inbound:"aead-method,omitempty"` + PaddingMin *int `inbound:"padding-min,omitempty"` + PaddingMax *int `inbound:"padding-max,omitempty"` + TableType string `inbound:"table-type,omitempty"` // "prefer_ascii" or "prefer_entropy" + HandshakeTimeoutSecond *int `inbound:"handshake-timeout,omitempty"` + EnablePureDownlink *bool `inbound:"enable-pure-downlink,omitempty"` + CustomTable string `inbound:"custom-table,omitempty"` // optional custom byte layout, e.g. xpxvvpvv + CustomTables []string `inbound:"custom-tables,omitempty"` + + // mihomo private extension (not the part of standard Sudoku protocol) + MuxOption MuxOption `inbound:"mux-option,omitempty"` } func (o SudokuOption) Equal(config C.InboundConfig) bool { @@ -31,7 +34,7 @@ func (o SudokuOption) Equal(config C.InboundConfig) bool { type Sudoku struct { *Base config *SudokuOption - listeners []*sudokuListener.Listener + listeners []*sudoku.Listener serverConf LC.SudokuServer } @@ -44,25 +47,20 @@ func NewSudoku(options *SudokuOption) (*Sudoku, error) { return nil, err } - defaultConf := apis.DefaultConfig() - serverConf := LC.SudokuServer{ - Enable: true, - Listen: base.RawAddress(), - Key: options.Key, - AEADMethod: options.AEADMethod, - PaddingMin: options.PaddingMin, - PaddingMax: options.PaddingMax, - Seed: options.Seed, - TableType: options.TableType, - } - if options.HandshakeTimeoutSecond != nil { - serverConf.HandshakeTimeoutSecond = options.HandshakeTimeoutSecond - } else { - // Use Sudoku default if not specified. - v := defaultConf.HandshakeTimeoutSeconds - serverConf.HandshakeTimeoutSecond = &v + Enable: true, + Listen: base.RawAddress(), + Key: options.Key, + AEADMethod: options.AEADMethod, + PaddingMin: options.PaddingMin, + PaddingMax: options.PaddingMax, + TableType: options.TableType, + HandshakeTimeoutSecond: options.HandshakeTimeoutSecond, + EnablePureDownlink: options.EnablePureDownlink, + CustomTable: options.CustomTable, + CustomTables: options.CustomTables, } + serverConf.MuxOption = options.MuxOption.Build() return &Sudoku{ Base: base, @@ -96,7 +94,7 @@ func (s *Sudoku) Listen(tunnel C.Tunnel) error { conf := s.serverConf conf.Listen = addr - l, err := sudokuListener.New(conf, tunnel, s.Additions()...) + l, err := sudoku.New(conf, tunnel, s.Additions()...) if err != nil { errs = append(errs, err) continue diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku_test.go b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku_test.go index 6d3e35b19e..6ba9e63b6b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku_test.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/inbound/sudoku_test.go @@ -6,9 +6,12 @@ import ( "github.com/metacubex/mihomo/adapter/outbound" "github.com/metacubex/mihomo/listener/inbound" + "github.com/metacubex/mihomo/transport/sudoku" "github.com/stretchr/testify/assert" ) +var sudokuPrivateKey, sudokuPublicKey, _ = sudoku.GenKeyPair() + func testInboundSudoku(t *testing.T, inboundOptions inbound.SudokuOption, outboundOptions outbound.SudokuOption) { t.Parallel() @@ -47,6 +50,8 @@ func testInboundSudoku(t *testing.T, inboundOptions inbound.SudokuOption, outbou defer out.Close() tunnel.DoTest(t, out) + + testSingMux(t, tunnel, out) } func TestInboundSudoku_Basic(t *testing.T) { @@ -58,6 +63,14 @@ func TestInboundSudoku_Basic(t *testing.T) { Key: key, } testInboundSudoku(t, inboundOptions, outboundOptions) + + t.Run("ed25519key", func(t *testing.T) { + inboundOptions := inboundOptions + outboundOptions := outboundOptions + inboundOptions.Key = sudokuPublicKey + outboundOptions.Key = sudokuPrivateKey + testInboundSudoku(t, inboundOptions, outboundOptions) + }) } func TestInboundSudoku_Entropy(t *testing.T) { @@ -71,21 +84,83 @@ func TestInboundSudoku_Entropy(t *testing.T) { TableType: "prefer_entropy", } testInboundSudoku(t, inboundOptions, outboundOptions) + + t.Run("ed25519key", func(t *testing.T) { + inboundOptions := inboundOptions + outboundOptions := outboundOptions + inboundOptions.Key = sudokuPublicKey + outboundOptions.Key = sudokuPrivateKey + testInboundSudoku(t, inboundOptions, outboundOptions) + }) } func TestInboundSudoku_Padding(t *testing.T) { key := "test_key_padding" - min := 10 - max := 100 + paddingMin := 10 + paddingMax := 100 inboundOptions := inbound.SudokuOption{ Key: key, - PaddingMin: &min, - PaddingMax: &max, + PaddingMin: &paddingMin, + PaddingMax: &paddingMax, } outboundOptions := outbound.SudokuOption{ Key: key, - PaddingMin: &min, - PaddingMax: &max, + PaddingMin: &paddingMin, + PaddingMax: &paddingMax, } testInboundSudoku(t, inboundOptions, outboundOptions) + + t.Run("ed25519key", func(t *testing.T) { + inboundOptions := inboundOptions + outboundOptions := outboundOptions + inboundOptions.Key = sudokuPublicKey + outboundOptions.Key = sudokuPrivateKey + testInboundSudoku(t, inboundOptions, outboundOptions) + }) +} + +func TestInboundSudoku_PackedDownlink(t *testing.T) { + key := "test_key_packed" + enablePure := false + inboundOptions := inbound.SudokuOption{ + Key: key, + EnablePureDownlink: &enablePure, + } + outboundOptions := outbound.SudokuOption{ + Key: key, + EnablePureDownlink: &enablePure, + } + testInboundSudoku(t, inboundOptions, outboundOptions) + + t.Run("ed25519key", func(t *testing.T) { + inboundOptions := inboundOptions + outboundOptions := outboundOptions + inboundOptions.Key = sudokuPublicKey + outboundOptions.Key = sudokuPrivateKey + testInboundSudoku(t, inboundOptions, outboundOptions) + }) +} + +func TestInboundSudoku_CustomTable(t *testing.T) { + key := "test_key_custom" + custom := "xpxvvpvv" + inboundOptions := inbound.SudokuOption{ + Key: key, + TableType: "prefer_entropy", + CustomTable: custom, + } + outboundOptions := outbound.SudokuOption{ + Key: key, + TableType: "prefer_entropy", + CustomTable: custom, + } + testInboundSudoku(t, inboundOptions, outboundOptions) + + t.Run("ed25519key", func(t *testing.T) { + inboundOptions := inboundOptions + outboundOptions := outboundOptions + inboundOptions.Key = sudokuPublicKey + outboundOptions.Key = sudokuPrivateKey + testInboundSudoku(t, inboundOptions, outboundOptions) + }) } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go b/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go index 3df49d2c5a..bc67a476e2 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/mixed/mixed.go @@ -9,7 +9,6 @@ import ( "github.com/metacubex/mihomo/component/auth" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" authStore "github.com/metacubex/mihomo/listener/auth" LC "github.com/metacubex/mihomo/listener/config" @@ -19,6 +18,8 @@ import ( "github.com/metacubex/mihomo/ntp" "github.com/metacubex/mihomo/transport/socks4" "github.com/metacubex/mihomo/transport/socks5" + + "github.com/metacubex/tls" ) type Listener struct { @@ -62,41 +63,43 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A return nil, err } - tlsConfig := &tlsC.Config{Time: ntp.Now} + tlsConfig := &tls.Config{Time: ntp.Now} var realityBuilder *reality.Builder if config.Certificate != "" && config.PrivateKey != "" { - cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) + certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey) if err != nil { return nil, err } - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() + } if config.EchKey != "" { - err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(config.EchKey, tlsConfig) if err != nil { return nil, err } } } - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType) + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType) if len(config.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(config.ClientAuthCert) if err != nil { return nil, err } tlsConfig.ClientCAs = pool } if config.RealityConfig.PrivateKey != "" { - if tlsConfig.Certificates != nil { + if tlsConfig.GetCertificate != nil { return nil, errors.New("certificate is unavailable in reality") } - if tlsConfig.ClientAuth != tlsC.NoClientCert { + if tlsConfig.ClientAuth != tls.NoClientCert { return nil, errors.New("client-auth is unavailable in reality") } realityBuilder, err = config.RealityConfig.Build(tunnel) @@ -107,8 +110,8 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A if realityBuilder != nil { l = realityBuilder.NewListener(l) - } else if len(tlsConfig.Certificates) > 0 { - l = tlsC.NewListener(l, tlsConfig) + } else if tlsConfig.GetCertificate != nil { + l = tls.NewListener(l, tlsConfig) } ml := &Listener{ diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_hysteria2/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_hysteria2/server.go index 2d172aab4f..493607d525 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_hysteria2/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_hysteria2/server.go @@ -5,8 +5,6 @@ import ( "errors" "fmt" "net" - "net/http" - "net/http/httputil" "net/url" "strings" @@ -15,17 +13,18 @@ import ( "github.com/metacubex/mihomo/common/sockopt" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing" "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/ntp" - "github.com/metacubex/sing-quic/hysteria2" - + "github.com/metacubex/http" + "github.com/metacubex/http/httputil" "github.com/metacubex/quic-go" + "github.com/metacubex/sing-quic/hysteria2" E "github.com/metacubex/sing/common/exceptions" + "github.com/metacubex/tls" ) type Listener struct { @@ -57,23 +56,25 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi sl = &Listener{false, config, nil, nil} - cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) + tlsConfig := &tls.Config{ + Time: ntp.Now, + MinVersion: tls.VersionTLS13, + } + certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey) if err != nil { return nil, err } - tlsConfig := &tlsC.Config{ - Time: ntp.Now, - MinVersion: tlsC.VersionTLS13, + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() } - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType) + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType) if len(config.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(config.ClientAuthCert) if err != nil { return nil, err } @@ -81,7 +82,7 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi } if config.EchKey != "" { - err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(config.EchKey, tlsConfig) if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/dns.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/dns.go index 82a9fdb6c1..317fefce2d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/dns.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/dns.go @@ -18,17 +18,11 @@ import ( "github.com/metacubex/sing/common/network" ) -type ListenerHandler struct { - *sing.ListenerHandler - DnsAdds []netip.AddrPort - DisableICMPForwarding bool -} - func (h *ListenerHandler) ShouldHijackDns(targetAddr netip.AddrPort) bool { if targetAddr.Addr().IsLoopback() && targetAddr.Port() == 53 { // cause by system stack return true } - for _, addrPort := range h.DnsAdds { + for _, addrPort := range h.DnsAddrPorts { if addrPort == targetAddr || (addrPort.Addr().IsUnspecified() && targetAddr.Port() == 53) { return true } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/prepare.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/prepare.go index e59947b84b..e97771c445 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/prepare.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/prepare.go @@ -2,6 +2,7 @@ package sing_tun import ( "context" + "net/netip" "time" "github.com/metacubex/mihomo/component/dialer" @@ -17,7 +18,7 @@ import ( func (h *ListenerHandler) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) { switch network { case N.NetworkICMP: // our fork only send those type to PrepareConnection now - if h.DisableICMPForwarding || resolver.IsFakeIP(destination.Addr) { // skip fakeip and if ICMP handling is disabled + if h.DisableICMPForwarding || h.skipPingForwardingByAddr(destination.Addr) { // skip if ICMP handling is disabled or other condition log.Infoln("[ICMP] %s %s --> %s using fake ping echo", network, source, destination) return nil, nil } @@ -32,3 +33,20 @@ func (h *ListenerHandler) PrepareConnection(network string, source M.Socksaddr, } return nil, nil } + +func (h *ListenerHandler) skipPingForwardingByAddr(addr netip.Addr) bool { + for _, prefix := range h.Inet4Address { // skip in interface ipv4 range + if prefix.Contains(addr) { + return true + } + } + for _, prefix := range h.Inet6Address { // skip in interface ipv6 range + if prefix.Contains(addr) { + return true + } + } + if resolver.IsFakeIP(addr) { // skip in fakeIp pool + return true + } + return false +} diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go index 87f413d431..41ba895b4a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go @@ -67,6 +67,14 @@ type Listener struct { dnsServerIp []string } +type ListenerHandler struct { + *sing.ListenerHandler + DnsAddrPorts []netip.AddrPort + Inet4Address []netip.Prefix + Inet6Address []netip.Prefix + DisableICMPForwarding bool +} + var emptyAddressSet = []*netipx.IPSet{{}} func CalculateInterfaceName(name string) (tunName string) { @@ -268,7 +276,9 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis handler := &ListenerHandler{ ListenerHandler: h, - DnsAdds: dnsAdds, + DnsAddrPorts: dnsAdds, + Inet4Address: options.Inet4Address, + Inet6Address: options.Inet6Address, DisableICMPForwarding: options.DisableICMPForwarding, } l = &Listener{ diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vless/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vless/server.go index a210d70a2d..83ba577924 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vless/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vless/server.go @@ -4,13 +4,11 @@ import ( "context" "errors" "net" - "net/http" "strings" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/reality" @@ -20,8 +18,10 @@ import ( "github.com/metacubex/mihomo/transport/vless/encryption" mihomoVMess "github.com/metacubex/mihomo/transport/vmess" + "github.com/metacubex/http" "github.com/metacubex/sing/common" "github.com/metacubex/sing/common/metadata" + "github.com/metacubex/tls" ) type Listener struct { @@ -76,42 +76,44 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) }() } - tlsConfig := &tlsC.Config{Time: ntp.Now} + tlsConfig := &tls.Config{Time: ntp.Now} var realityBuilder *reality.Builder var httpServer http.Server if config.Certificate != "" && config.PrivateKey != "" { - cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) + certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey) if err != nil { return nil, err } - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() + } if config.EchKey != "" { - err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(config.EchKey, tlsConfig) if err != nil { return nil, err } } } - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType) + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType) if len(config.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(config.ClientAuthCert) if err != nil { return nil, err } tlsConfig.ClientCAs = pool } if config.RealityConfig.PrivateKey != "" { - if tlsConfig.Certificates != nil { + if tlsConfig.GetCertificate != nil { return nil, errors.New("certificate is unavailable in reality") } - if tlsConfig.ClientAuth != tlsC.NoClientCert { + if tlsConfig.ClientAuth != tls.NoClientCert { return nil, errors.New("client-auth is unavailable in reality") } realityBuilder, err = config.RealityConfig.Build(tunnel) @@ -153,12 +155,8 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) } if realityBuilder != nil { l = realityBuilder.NewListener(l) - } else if len(tlsConfig.Certificates) > 0 { - if httpServer.Handler != nil { - l = tlsC.NewListenerForHttps(l, &httpServer, tlsConfig) - } else { - l = tlsC.NewListener(l, tlsConfig) - } + } else if tlsConfig.GetCertificate != nil { + l = tls.NewListener(l, tlsConfig) } else if sl.decryption == nil { return nil, errors.New("disallow using Vless without any certificates/reality/decryption config") } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go index 24c323baab..7dd0a163ba 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_vmess/server.go @@ -4,14 +4,12 @@ import ( "context" "errors" "net" - "net/http" "net/url" "strings" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/reality" @@ -20,9 +18,11 @@ import ( "github.com/metacubex/mihomo/transport/gun" mihomoVMess "github.com/metacubex/mihomo/transport/vmess" + "github.com/metacubex/http" vmess "github.com/metacubex/sing-vmess" "github.com/metacubex/sing/common" "github.com/metacubex/sing/common/metadata" + "github.com/metacubex/tls" ) type Listener struct { @@ -76,42 +76,44 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) sl = &Listener{false, config, nil, service} - tlsConfig := &tlsC.Config{Time: ntp.Now} + tlsConfig := &tls.Config{Time: ntp.Now} var realityBuilder *reality.Builder var httpServer http.Server if config.Certificate != "" && config.PrivateKey != "" { - cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) + certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey) if err != nil { return nil, err } - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() + } if config.EchKey != "" { - err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(config.EchKey, tlsConfig) if err != nil { return nil, err } } } - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType) + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType) if len(config.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(config.ClientAuthCert) if err != nil { return nil, err } tlsConfig.ClientCAs = pool } if config.RealityConfig.PrivateKey != "" { - if tlsConfig.Certificates != nil { + if tlsConfig.GetCertificate != nil { return nil, errors.New("certificate is unavailable in reality") } - if tlsConfig.ClientAuth != tlsC.NoClientCert { + if tlsConfig.ClientAuth != tls.NoClientCert { return nil, errors.New("client-auth is unavailable in reality") } realityBuilder, err = config.RealityConfig.Build(tunnel) @@ -153,12 +155,8 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) } if realityBuilder != nil { l = realityBuilder.NewListener(l) - } else if len(tlsConfig.Certificates) > 0 { - if httpServer.Handler != nil { - l = tlsC.NewListenerForHttps(l, &httpServer, tlsConfig) - } else { - l = tlsC.NewListener(l, tlsConfig) - } + } else if tlsConfig.GetCertificate != nil { + l = tls.NewListener(l, tlsConfig) } sl.listeners = append(sl.listeners, l) diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/socks/tcp.go b/clash-meta-android/core/src/foss/golang/clash/listener/socks/tcp.go index 60eaa7411c..45de213530 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/socks/tcp.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/socks/tcp.go @@ -10,7 +10,6 @@ import ( "github.com/metacubex/mihomo/component/auth" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" authStore "github.com/metacubex/mihomo/listener/auth" LC "github.com/metacubex/mihomo/listener/config" @@ -18,6 +17,8 @@ import ( "github.com/metacubex/mihomo/ntp" "github.com/metacubex/mihomo/transport/socks4" "github.com/metacubex/mihomo/transport/socks5" + + "github.com/metacubex/tls" ) type Listener struct { @@ -61,41 +62,43 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A return nil, err } - tlsConfig := &tlsC.Config{Time: ntp.Now} + tlsConfig := &tls.Config{Time: ntp.Now} var realityBuilder *reality.Builder if config.Certificate != "" && config.PrivateKey != "" { - cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) + certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey) if err != nil { return nil, err } - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() + } if config.EchKey != "" { - err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(config.EchKey, tlsConfig) if err != nil { return nil, err } } } - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType) + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType) if len(config.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(config.ClientAuthCert) if err != nil { return nil, err } tlsConfig.ClientCAs = pool } if config.RealityConfig.PrivateKey != "" { - if tlsConfig.Certificates != nil { + if tlsConfig.GetCertificate != nil { return nil, errors.New("certificate is unavailable in reality") } - if tlsConfig.ClientAuth != tlsC.NoClientCert { + if tlsConfig.ClientAuth != tls.NoClientCert { return nil, errors.New("client-auth is unavailable in reality") } realityBuilder, err = config.RealityConfig.Build(tunnel) @@ -106,8 +109,8 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A if realityBuilder != nil { l = realityBuilder.NewListener(l) - } else if len(tlsConfig.Certificates) > 0 { - l = tlsC.NewListener(l, tlsConfig) + } else if tlsConfig.GetCertificate != nil { + l = tls.NewListener(l, tlsConfig) } sl := &Listener{ diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sudoku/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sudoku/server.go index 87b2abd9d3..e90e231c1d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sudoku/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sudoku/server.go @@ -1,23 +1,26 @@ package sudoku import ( + "errors" + "io" "net" "strings" - "github.com/saba-futai/sudoku/apis" - sudokuobfs "github.com/saba-futai/sudoku/pkg/obfs/sudoku" - "github.com/metacubex/mihomo/adapter/inbound" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/sudoku" ) type Listener struct { listener net.Listener addr string closed bool - protoConf apis.ProtocolConfig + protoConf sudoku.ProtocolConfig + handler *sing.ListenerHandler } // RawAddress implements C.Listener @@ -43,19 +46,75 @@ func (l *Listener) Close() error { } func (l *Listener) handleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { - tunnelConn, target, err := apis.ServerHandshake(conn, &l.protoConf) + session, err := sudoku.ServerHandshake(conn, &l.protoConf) if err != nil { _ = conn.Close() return } - targetAddr := socks5.ParseAddr(target) - if targetAddr == nil { - _ = tunnelConn.Close() - return + switch session.Type { + case sudoku.SessionTypeUoT: + l.handleUoTSession(session.Conn, tunnel, additions...) + default: + targetAddr := socks5.ParseAddr(session.Target) + if targetAddr == nil { + _ = session.Conn.Close() + return + } + l.handler.HandleSocket(targetAddr, session.Conn, additions...) + //tunnel.HandleTCPConn(inbound.NewSocket(targetAddr, session.Conn, C.SUDOKU, additions...)) } +} - tunnel.HandleTCPConn(inbound.NewSocket(targetAddr, tunnelConn, C.SUDOKU, additions...)) +func (l *Listener) handleUoTSession(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { + writer := sudoku.NewUoTPacketConn(conn) + remoteAddr := conn.RemoteAddr() + + for { + addrStr, payload, err := sudoku.ReadDatagram(conn) + if err != nil { + if !errors.Is(err, io.EOF) { + log.Debugln("[Sudoku][UoT] session closed: %v", err) + } + _ = conn.Close() + return + } + + target := socks5.ParseAddr(addrStr) + if target == nil { + log.Debugln("[Sudoku][UoT] drop invalid target: %s", addrStr) + continue + } + + packet := &uotPacket{ + payload: payload, + writer: writer, + rAddr: remoteAddr, + } + tunnel.HandleUDPPacket(inbound.NewPacket(target, packet, C.SUDOKU, additions...)) + } +} + +type uotPacket struct { + payload []byte + writer *sudoku.UoTPacketConn + rAddr net.Addr +} + +func (p *uotPacket) Data() []byte { + return p.payload +} + +func (p *uotPacket) WriteBack(b []byte, addr net.Addr) (int, error) { + return p.writer.WriteTo(b, addr) +} + +func (p *uotPacket) Drop() { + p.payload = nil +} + +func (p *uotPacket) LocalAddr() net.Addr { + return p.rAddr } func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { @@ -66,14 +125,20 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition) } } - l, err := inbound.Listen("tcp", config.Listen) + // Using sing handler for sing-mux support + h, err := sing.NewListenerHandler(sing.ListenerConfig{ + Tunnel: tunnel, + Type: C.SUDOKU, + Additions: additions, + MuxOption: config.MuxOption, + }) if err != nil { return nil, err } - seed := config.Seed - if seed == "" { - seed = config.Key + l, err := inbound.Listen("tcp", config.Listen) + if err != nil { + return nil, err } tableType := strings.ToLower(config.TableType) @@ -81,9 +146,7 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition) tableType = "prefer_ascii" } - table := sudokuobfs.NewTable(seed, tableType) - - defaultConf := apis.DefaultConfig() + defaultConf := sudoku.DefaultConfig() paddingMin := defaultConf.PaddingMin paddingMax := defaultConf.PaddingMax if config.PaddingMin != nil { @@ -98,20 +161,35 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition) if config.PaddingMax == nil && config.PaddingMin != nil && paddingMax < paddingMin { paddingMax = paddingMin } + enablePureDownlink := defaultConf.EnablePureDownlink + if config.EnablePureDownlink != nil { + enablePureDownlink = *config.EnablePureDownlink + } + + tables, err := sudoku.NewTablesWithCustomPatterns(config.Key, tableType, config.CustomTable, config.CustomTables) + if err != nil { + _ = l.Close() + return nil, err + } handshakeTimeout := defaultConf.HandshakeTimeoutSeconds if config.HandshakeTimeoutSecond != nil { handshakeTimeout = *config.HandshakeTimeoutSecond } - protoConf := apis.ProtocolConfig{ + protoConf := sudoku.ProtocolConfig{ Key: config.Key, AEADMethod: defaultConf.AEADMethod, - Table: table, PaddingMin: paddingMin, PaddingMax: paddingMax, + EnablePureDownlink: enablePureDownlink, HandshakeTimeoutSeconds: handshakeTimeout, } + if len(tables) == 1 { + protoConf.Table = tables[0] + } else { + protoConf.Tables = tables + } if config.AEADMethod != "" { protoConf.AEADMethod = config.AEADMethod } @@ -120,6 +198,7 @@ func New(config LC.SudokuServer, tunnel C.Tunnel, additions ...inbound.Addition) listener: l, addr: config.Listen, protoConf: protoConf, + handler: h, } go func() { diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/trojan/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/trojan/server.go index 03fb02cfcb..e3c1002c9f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/trojan/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/trojan/server.go @@ -4,13 +4,11 @@ import ( "errors" "io" "net" - "net/http" "strings" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/reality" @@ -22,7 +20,9 @@ import ( "github.com/metacubex/mihomo/transport/trojan" mihomoVMess "github.com/metacubex/mihomo/transport/vmess" + "github.com/metacubex/http" "github.com/metacubex/smux" + "github.com/metacubex/tls" ) type Listener struct { @@ -71,42 +71,44 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition) } sl = &Listener{false, config, nil, keys, pickCipher, h} - tlsConfig := &tlsC.Config{Time: ntp.Now} + tlsConfig := &tls.Config{Time: ntp.Now} var realityBuilder *reality.Builder var httpServer http.Server if config.Certificate != "" && config.PrivateKey != "" { - cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) + certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey) if err != nil { return nil, err } - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() + } if config.EchKey != "" { - err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(config.EchKey, tlsConfig) if err != nil { return nil, err } } } - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType) + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType) if len(config.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(config.ClientAuthCert) if err != nil { return nil, err } tlsConfig.ClientCAs = pool } if config.RealityConfig.PrivateKey != "" { - if tlsConfig.Certificates != nil { + if tlsConfig.GetCertificate != nil { return nil, errors.New("certificate is unavailable in reality") } - if tlsConfig.ClientAuth != tlsC.NoClientCert { + if tlsConfig.ClientAuth != tls.NoClientCert { return nil, errors.New("client-auth is unavailable in reality") } realityBuilder, err = config.RealityConfig.Build(tunnel) @@ -148,12 +150,8 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition) } if realityBuilder != nil { l = realityBuilder.NewListener(l) - } else if len(tlsConfig.Certificates) > 0 { - if httpServer.Handler != nil { - l = tlsC.NewListenerForHttps(l, &httpServer, tlsConfig) - } else { - l = tlsC.NewListener(l, tlsConfig) - } + } else if tlsConfig.GetCertificate != nil { + l = tls.NewListener(l, tlsConfig) } else if !config.TrojanSSOption.Enabled { return nil, errors.New("disallow using Trojan without both certificates/reality/ss config") } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/tuic/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/tuic/server.go index f105c51ac3..7e659e596a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/tuic/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/tuic/server.go @@ -9,7 +9,6 @@ import ( "github.com/metacubex/mihomo/common/sockopt" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" LC "github.com/metacubex/mihomo/listener/config" "github.com/metacubex/mihomo/listener/sing" @@ -20,6 +19,7 @@ import ( "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" + "github.com/metacubex/tls" "golang.org/x/exp/slices" ) @@ -49,23 +49,25 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( return nil, err } - cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) + tlsConfig := &tls.Config{ + Time: ntp.Now, + MinVersion: tls.VersionTLS13, + } + certLoader, err := ca.NewTLSKeyPairLoader(config.Certificate, config.PrivateKey) if err != nil { return nil, err } - tlsConfig := &tlsC.Config{ - Time: ntp.Now, - MinVersion: tlsC.VersionTLS13, + tlsConfig.GetCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { + return certLoader() } - tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} - tlsConfig.ClientAuth = tlsC.ClientAuthTypeFromString(config.ClientAuthType) + tlsConfig.ClientAuth = ca.ClientAuthTypeFromString(config.ClientAuthType) if len(config.ClientAuthCert) > 0 { - if tlsConfig.ClientAuth == tlsC.NoClientCert { - tlsConfig.ClientAuth = tlsC.RequireAndVerifyClientCert + if tlsConfig.ClientAuth == tls.NoClientCert { + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert } } - if tlsConfig.ClientAuth == tlsC.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tlsC.RequireAndVerifyClientCert { - pool, err := ca.LoadCertificates(config.ClientAuthCert, C.Path) + if tlsConfig.ClientAuth == tls.VerifyClientCertIfGiven || tlsConfig.ClientAuth == tls.RequireAndVerifyClientCert { + pool, err := ca.LoadCertificates(config.ClientAuthCert) if err != nil { return nil, err } @@ -73,7 +75,7 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( } if config.EchKey != "" { - err = ech.LoadECHKey(config.EchKey, tlsConfig, C.Path) + err = ech.LoadECHKey(config.EchKey, tlsConfig) if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/ntp/ntp/service.go b/clash-meta-android/core/src/foss/golang/clash/ntp/ntp/service.go index 8f27d0aac1..97918548fd 100644 --- a/clash-meta-android/core/src/foss/golang/clash/ntp/ntp/service.go +++ b/clash-meta-android/core/src/foss/golang/clash/ntp/ntp/service.go @@ -7,6 +7,7 @@ import ( "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" mihomoNtp "github.com/metacubex/mihomo/ntp" @@ -36,9 +37,13 @@ func ReCreateNTPService(server string, interval time.Duration, dialerProxy strin return } ctx, cancel := context.WithCancel(context.Background()) + var cDialer C.Dialer = dialer.NewDialer() + if dialerProxy != "" { + cDialer = proxydialer.NewByName(dialerProxy) + } globalSrv = &Service{ server: M.ParseSocksaddr(server), - dialer: proxydialer.NewByNameSingDialer(dialerProxy, dialer.NewDialer()), + dialer: proxydialer.NewSingDialer(cDialer), ticker: time.NewTicker(interval * time.Minute), ctx: ctx, cancel: cancel, diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gost-plugin/websocket.go b/clash-meta-android/core/src/foss/golang/clash/transport/gost-plugin/websocket.go index fbe1ec32d9..c668c189b0 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gost-plugin/websocket.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gost-plugin/websocket.go @@ -2,14 +2,15 @@ package gost import ( "context" - "crypto/tls" "net" - "net/http" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" "github.com/metacubex/mihomo/transport/vmess" - smux "github.com/metacubex/smux" + + "github.com/metacubex/http" + "github.com/metacubex/smux" + "github.com/metacubex/tls" ) // Option is options of gost websocket diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go index 08598b2552..3ac548ddfc 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/gun.go @@ -6,15 +6,13 @@ package gun import ( "bufio" "context" - "crypto/tls" "encoding/binary" "errors" "fmt" "io" "net" - "net/http" - "net/http/httptrace" "net/url" + "strings" "sync" "time" @@ -24,7 +22,9 @@ import ( tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" - "golang.org/x/net/http2" + "github.com/metacubex/http" + "github.com/metacubex/http/httptrace" + "github.com/metacubex/tls" ) var ( @@ -260,35 +260,34 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri } if clientFingerprint, ok := tlsC.GetFingerprint(clientFingerprint); ok { - tlsConfig := tlsC.UConfig(cfg) - err := echConfig.ClientHandle(ctx, tlsConfig) - if err != nil { - pconn.Close() - return nil, err - } - if realityConfig == nil { + tlsConfig := tlsC.UConfig(cfg) + err := echConfig.ClientHandleUTLS(ctx, tlsConfig) + if err != nil { + pconn.Close() + return nil, err + } tlsConn := tlsC.UClient(pconn, tlsConfig, clientFingerprint) if err := tlsConn.HandshakeContext(ctx); err != nil { pconn.Close() return nil, err } state := tlsConn.ConnectionState() - if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { + if p := state.NegotiatedProtocol; p != http.Http2NextProtoTLS { tlsConn.Close() - return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) + return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http.Http2NextProtoTLS) } return tlsConn, nil } else { - realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, tlsConfig, realityConfig) + realityConn, err := tlsC.GetRealityConn(ctx, pconn, clientFingerprint, cfg.ServerName, realityConfig) if err != nil { pconn.Close() return nil, err } //state := realityConn.(*utls.UConn).ConnectionState() - //if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { + //if p := state.NegotiatedProtocol; p != http.Http2NextProtoTLS { // realityConn.Close() - // return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) + // return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http.Http2NextProtoTLS) //} return realityConn, nil } @@ -297,25 +296,10 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint") } - if echConfig != nil { - tlsConfig := tlsC.UConfig(cfg) - err := echConfig.ClientHandle(ctx, tlsConfig) - if err != nil { - pconn.Close() - return nil, err - } - - conn := tlsC.Client(pconn, tlsConfig) - if err := conn.HandshakeContext(ctx); err != nil { - pconn.Close() - return nil, err - } - state := conn.ConnectionState() - if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { - conn.Close() - return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) - } - return conn, nil + err = echConfig.ClientHandle(ctx, cfg) + if err != nil { + pconn.Close() + return nil, err } conn := tls.Client(pconn, cfg) @@ -324,14 +308,14 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri return nil, err } state := conn.ConnectionState() - if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { + if p := state.NegotiatedProtocol; p != http.Http2NextProtoTLS { conn.Close() - return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) + return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http.Http2NextProtoTLS) } return conn, nil } - transport := &http2.Transport{ + transport := &http.Http2Transport{ DialTLSContext: dialFunc, TLSClientConfig: tlsConfig, AllowHTTP: false, @@ -341,18 +325,26 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri ctx, cancel := context.WithCancel(context.Background()) wrap := &TransportWrap{ - Transport: transport, - ctx: ctx, - cancel: cancel, + Http2Transport: transport, + ctx: ctx, + cancel: cancel, } return wrap } +func ServiceNameToPath(serviceName string) string { + if strings.HasPrefix(serviceName, "/") { // custom paths + return serviceName + } + return "/" + serviceName + "/Tun" +} + func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, error) { serviceName := "GunService" if cfg.ServiceName != "" { serviceName = cfg.ServiceName } + path := ServiceNameToPath(serviceName) reader, writer := io.Pipe() request := &http.Request{ @@ -361,9 +353,9 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er URL: &url.URL{ Scheme: "https", Host: cfg.Host, - Path: fmt.Sprintf("/%s/Tun", serviceName), + Path: path, // for unescape path - Opaque: fmt.Sprintf("//%s/%s/Tun", cfg.Host, serviceName), + Opaque: "//" + cfg.Host + path, }, Proto: "HTTP/2", ProtoMajor: 2, diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/server.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/server.go index 953c487816..c240459fee 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gun/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/server.go @@ -3,7 +3,6 @@ package gun import ( "io" "net" - "net/http" "strings" "sync" "time" @@ -12,8 +11,8 @@ import ( N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" + "github.com/metacubex/http" + "github.com/metacubex/http/h2c" ) const idleTimeout = 30 * time.Second @@ -25,7 +24,7 @@ type ServerOption struct { } func NewServerHandler(options ServerOption) http.Handler { - path := "/" + options.ServiceName + "/Tun" + path := ServiceNameToPath(options.ServiceName) connHandler := options.ConnHandler httpHandler := options.HttpHandler if httpHandler == nil { @@ -72,7 +71,7 @@ func NewServerHandler(options ServerOption) http.Handler { } httpHandler.ServeHTTP(writer, request) - }), &http2.Server{ + }), &http.Http2Server{ IdleTimeout: idleTimeout, }) } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go index 9c5c437560..5925b35239 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport.go @@ -5,11 +5,11 @@ import ( "net" "sync" - "golang.org/x/net/http2" + "github.com/metacubex/http" ) type TransportWrap struct { - *http2.Transport + *http.Http2Transport ctx context.Context cancel context.CancelFunc closeOnce sync.Once @@ -18,7 +18,7 @@ type TransportWrap struct { func (tw *TransportWrap) Close() error { tw.closeOnce.Do(func() { tw.cancel() - closeTransport(tw.Transport) + closeTransport(tw.Http2Transport) }) return nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport_close.go b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport_close.go index 2b30ed7cdd..b9c7613446 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport_close.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/gun/transport_close.go @@ -2,21 +2,20 @@ package gun import ( "net" - "net/http" "sync" "time" "unsafe" - "golang.org/x/net/http2" + "github.com/metacubex/http" ) type clientConnPool struct { - t *http2.Transport + t *http.Http2Transport mu sync.Mutex - conns map[string][]*http2.ClientConn // key is host:port - dialing map[string]unsafe.Pointer // currently in-flight dials - keys map[*http2.ClientConn][]string + conns map[string][]*http.Http2ClientConn // key is host:port + dialing map[string]unsafe.Pointer // currently in-flight dials + keys map[*http.Http2ClientConn][]string addConnCalls map[string]unsafe.Pointer // in-flight addConnIfNeeded calls } @@ -35,7 +34,7 @@ type tlsConn interface { NetConn() net.Conn } -func closeClientConn(cc *http2.ClientConn) { // like forceCloseConn() in http2.ClientConn but also apply for tls-like conn +func closeClientConn(cc *http.Http2ClientConn) { // like forceCloseConn() in http.Http2ClientConn but also apply for tls-like conn if conn, ok := (*clientConn)(unsafe.Pointer(cc)).tconn.(tlsConn); ok { t := time.AfterFunc(time.Second, func() { _ = conn.NetConn().Close() @@ -45,7 +44,7 @@ func closeClientConn(cc *http2.ClientConn) { // like forceCloseConn() in http2.C _ = cc.Close() } -func closeTransport(tr *http2.Transport) { +func closeTransport(tr *http.Http2Transport) { connPool := transportConnPool(tr) p := (*clientConnPool)((*efaceWords)(unsafe.Pointer(&connPool)).data) p.mu.Lock() @@ -56,9 +55,9 @@ func closeTransport(tr *http2.Transport) { } } // cleanup - p.conns = make(map[string][]*http2.ClientConn) - p.keys = make(map[*http2.ClientConn][]string) + p.conns = make(map[string][]*http.Http2ClientConn) + p.keys = make(map[*http.Http2ClientConn][]string) } -//go:linkname transportConnPool golang.org/x/net/http2.(*Transport).connPool -func transportConnPool(t *http2.Transport) http2.ClientConnPool +//go:linkname transportConnPool github.com/metacubex/http.(*http2Transport).connPool +func transportConnPool(t *http.Http2Transport) http.Http2ClientConnPool diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/conns/faketcp/tcp_test.go b/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/conns/faketcp/tcp_test.go deleted file mode 100644 index 03f73afb8c..0000000000 --- a/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/conns/faketcp/tcp_test.go +++ /dev/null @@ -1,192 +0,0 @@ -//go:build linux -// +build linux - -package faketcp - -import ( - _ "net/http/pprof" -) - -//const testPortStream = "127.0.0.1:3456" -//const testPortPacket = "127.0.0.1:3457" - -const testPortStream = "127.0.0.1:3456" -const portServerPacket = "[::]:3457" -const portRemotePacket = "127.0.0.1:3457" - -//func init() { -// startTCPServer() -// startTCPRawServer() -// go func() { -// log.Println(http.ListenAndServe("0.0.0.0:6060", nil)) -// }() -//} -// -//func startTCPServer() net.Listener { -// l, err := net.Listen("tcp", testPortStream) -// if err != nil { -// log.Panicln(err) -// } -// -// go func() { -// defer l.Close() -// for { -// conn, err := l.Accept() -// if err != nil { -// log.Println(err) -// return -// } -// -// go handleRequest(conn) -// } -// }() -// return l -//} -// -//func startTCPRawServer() *TCPConn { -// conn, err := Listen("tcp", portServerPacket) -// if err != nil { -// log.Panicln(err) -// } -// err = conn.SetReadBuffer(1024 * 1024) -// if err != nil { -// log.Println(err) -// } -// err = conn.SetWriteBuffer(1024 * 1024) -// if err != nil { -// log.Println(err) -// } -// -// go func() { -// defer conn.Close() -// buf := make([]byte, 1024) -// for { -// n, addr, err := conn.ReadFrom(buf) -// if err != nil { -// log.Println("server readfrom:", err) -// return -// } -// //echo -// n, err = conn.WriteTo(buf[:n], addr) -// if err != nil { -// log.Println("server writeTo:", err) -// return -// } -// } -// }() -// return conn -//} -// -//func handleRequest(conn net.Conn) { -// defer conn.Close() -// -// for { -// buf := make([]byte, 1024) -// size, err := conn.Read(buf) -// if err != nil { -// log.Println("handleRequest:", err) -// return -// } -// data := buf[:size] -// conn.Write(data) -// } -//} -// -//func TestDialTCPStream(t *testing.T) { -// conn, err := Dial("tcp", testPortStream) -// if err != nil { -// t.Fatal(err) -// } -// defer conn.Close() -// -// addr, err := net.ResolveTCPAddr("tcp", testPortStream) -// if err != nil { -// t.Fatal(err) -// } -// -// n, err := conn.WriteTo([]byte("abc"), addr) -// if err != nil { -// t.Fatal(n, err) -// } -// -// buf := make([]byte, 1024) -// if n, addr, err := conn.ReadFrom(buf); err != nil { -// t.Fatal(n, addr, err) -// } else { -// log.Println(string(buf[:n]), "from:", addr) -// } -//} -// -//func TestDialToTCPPacket(t *testing.T) { -// conn, err := Dial("tcp", portRemotePacket) -// if err != nil { -// t.Fatal(err) -// } -// defer conn.Close() -// -// addr, err := net.ResolveTCPAddr("tcp", portRemotePacket) -// if err != nil { -// t.Fatal(err) -// } -// -// n, err := conn.WriteTo([]byte("abc"), addr) -// if err != nil { -// t.Fatal(n, err) -// } -// log.Println("written") -// -// buf := make([]byte, 1024) -// log.Println("readfrom buf") -// if n, addr, err := conn.ReadFrom(buf); err != nil { -// log.Println(err) -// t.Fatal(n, addr, err) -// } else { -// log.Println(string(buf[:n]), "from:", addr) -// } -// -// log.Println("complete") -//} -// -//func TestSettings(t *testing.T) { -// conn, err := Dial("tcp", portRemotePacket) -// if err != nil { -// t.Fatal(err) -// } -// defer conn.Close() -// if err := conn.SetDSCP(46); err != nil { -// log.Fatal("SetDSCP:", err) -// } -// if err := conn.SetReadBuffer(4096); err != nil { -// log.Fatal("SetReaderBuffer:", err) -// } -// if err := conn.SetWriteBuffer(4096); err != nil { -// log.Fatal("SetWriteBuffer:", err) -// } -//} -// -//func BenchmarkEcho(b *testing.B) { -// conn, err := Dial("tcp", portRemotePacket) -// if err != nil { -// b.Fatal(err) -// } -// defer conn.Close() -// -// addr, err := net.ResolveTCPAddr("tcp", portRemotePacket) -// if err != nil { -// b.Fatal(err) -// } -// -// buf := make([]byte, 1024) -// b.ReportAllocs() -// b.SetBytes(int64(len(buf))) -// for i := 0; i < b.N; i++ { -// n, err := conn.WriteTo(buf, addr) -// if err != nil { -// b.Fatal(n, err) -// } -// -// if n, addr, err := conn.ReadFrom(buf); err != nil { -// b.Fatal(n, addr, err) -// } -// } -//} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/core/client.go b/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/core/client.go index 13c8db7502..3e72db64d7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/core/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/core/client.go @@ -9,7 +9,6 @@ import ( "sync" "time" - tlsC "github.com/metacubex/mihomo/component/tls" "github.com/metacubex/mihomo/transport/hysteria/obfs" "github.com/metacubex/mihomo/transport/hysteria/pmtud_fix" "github.com/metacubex/mihomo/transport/hysteria/transport" @@ -18,6 +17,7 @@ import ( "github.com/metacubex/quic-go" "github.com/metacubex/quic-go/congestion" "github.com/metacubex/randv2" + "github.com/metacubex/tls" ) var ( @@ -36,7 +36,7 @@ type Client struct { congestionFactory CongestionFactory obfuscator obfs.Obfuscator - tlsConfig *tlsC.Config + tlsConfig *tls.Config quicConfig *quic.Config quicSession *quic.Conn @@ -50,7 +50,7 @@ type Client struct { fastOpen bool } -func NewClient(serverAddr string, serverPorts string, protocol string, auth []byte, tlsConfig *tlsC.Config, quicConfig *quic.Config, +func NewClient(serverAddr string, serverPorts string, protocol string, auth []byte, tlsConfig *tls.Config, quicConfig *quic.Config, transport *transport.ClientTransport, sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory, obfuscator obfs.Obfuscator, hopInterval time.Duration, fastOpen bool) (*Client, error) { quicConfig.DisablePathMTUDiscovery = quicConfig.DisablePathMTUDiscovery || pmtud_fix.DisablePathMTUDiscovery diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/transport/client.go b/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/transport/client.go index 67f826a320..f30ee58f6e 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/transport/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/hysteria/transport/client.go @@ -5,7 +5,6 @@ import ( "net" "time" - tlsC "github.com/metacubex/mihomo/component/tls" "github.com/metacubex/mihomo/transport/hysteria/conns/faketcp" "github.com/metacubex/mihomo/transport/hysteria/conns/udp" "github.com/metacubex/mihomo/transport/hysteria/conns/wechat" @@ -13,6 +12,7 @@ import ( "github.com/metacubex/mihomo/transport/hysteria/utils" "github.com/metacubex/quic-go" + "github.com/metacubex/tls" ) type ClientTransport struct{} @@ -62,7 +62,7 @@ func (ct *ClientTransport) quicPacketConn(proto string, rAddr net.Addr, serverPo } } -func (ct *ClientTransport) QUICDial(proto string, server string, serverPorts string, tlsConfig *tlsC.Config, quicConfig *quic.Config, obfs obfsPkg.Obfuscator, hopInterval time.Duration, dialer utils.PacketDialer) (*quic.Conn, error) { +func (ct *ClientTransport) QUICDial(proto string, server string, serverPorts string, tlsConfig *tls.Config, quicConfig *quic.Config, obfs obfsPkg.Obfuscator, hopInterval time.Duration, dialer utils.PacketDialer) (*quic.Conn, error) { serverUDPAddr, err := dialer.RemoteAddr(server) if err != nil { return nil, err diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/shadowtls/shadowtls.go b/clash-meta-android/core/src/foss/golang/clash/transport/shadowtls/shadowtls.go index a0a3d7fb7e..adbe915ba7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/shadowtls/shadowtls.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/shadowtls/shadowtls.go @@ -4,7 +4,6 @@ import ( "context" "crypto/hmac" "crypto/sha1" - "crypto/tls" "encoding/binary" "fmt" "hash" @@ -13,6 +12,8 @@ import ( "github.com/metacubex/mihomo/common/pool" C "github.com/metacubex/mihomo/constant" + + "github.com/metacubex/tls" ) const ( diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/simple-obfs/http.go b/clash-meta-android/core/src/foss/golang/clash/transport/simple-obfs/http.go index 9c3f8e0029..b5b31dccf6 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/simple-obfs/http.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/simple-obfs/http.go @@ -7,10 +7,10 @@ import ( "fmt" "io" "net" - "net/http" "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/http" "github.com/metacubex/randv2" ) diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sing-shadowtls/shadowtls.go b/clash-meta-android/core/src/foss/golang/clash/transport/sing-shadowtls/shadowtls.go index 501e080f41..adf827e2be 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/sing-shadowtls/shadowtls.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sing-shadowtls/shadowtls.go @@ -2,7 +2,6 @@ package sing_shadowtls import ( "context" - "crypto/tls" "net" "github.com/metacubex/mihomo/component/ca" @@ -10,6 +9,7 @@ import ( "github.com/metacubex/mihomo/log" "github.com/metacubex/sing-shadowtls" + "github.com/metacubex/tls" "golang.org/x/exp/slices" ) diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/address.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/address.go new file mode 100644 index 0000000000..48b322967f --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/address.go @@ -0,0 +1,91 @@ +package sudoku + +import ( + "encoding/binary" + "fmt" + "io" + "net" + "strconv" +) + +func EncodeAddress(rawAddr string) ([]byte, error) { + host, portStr, err := net.SplitHostPort(rawAddr) + if err != nil { + return nil, err + } + + portInt, err := strconv.ParseUint(portStr, 10, 16) + if err != nil { + return nil, err + } + + var buf []byte + if ip := net.ParseIP(host); ip != nil { + if ip4 := ip.To4(); ip4 != nil { + buf = append(buf, 0x01) // IPv4 + buf = append(buf, ip4...) + } else { + buf = append(buf, 0x04) // IPv6 + buf = append(buf, ip...) + } + } else { + if len(host) > 255 { + return nil, fmt.Errorf("domain too long") + } + buf = append(buf, 0x03) // domain + buf = append(buf, byte(len(host))) + buf = append(buf, host...) + } + + var portBytes [2]byte + binary.BigEndian.PutUint16(portBytes[:], uint16(portInt)) + buf = append(buf, portBytes[:]...) + return buf, nil +} + +func DecodeAddress(r io.Reader) (string, error) { + var atyp [1]byte + if _, err := io.ReadFull(r, atyp[:]); err != nil { + return "", err + } + + switch atyp[0] { + case 0x01: // IPv4 + var ipBuf [net.IPv4len]byte + if _, err := io.ReadFull(r, ipBuf[:]); err != nil { + return "", err + } + var portBuf [2]byte + if _, err := io.ReadFull(r, portBuf[:]); err != nil { + return "", err + } + return net.JoinHostPort(net.IP(ipBuf[:]).String(), fmt.Sprint(binary.BigEndian.Uint16(portBuf[:]))), nil + case 0x04: // IPv6 + var ipBuf [net.IPv6len]byte + if _, err := io.ReadFull(r, ipBuf[:]); err != nil { + return "", err + } + var portBuf [2]byte + if _, err := io.ReadFull(r, portBuf[:]); err != nil { + return "", err + } + return net.JoinHostPort(net.IP(ipBuf[:]).String(), fmt.Sprint(binary.BigEndian.Uint16(portBuf[:]))), nil + case 0x03: // domain + var lengthBuf [1]byte + if _, err := io.ReadFull(r, lengthBuf[:]); err != nil { + return "", err + } + l := int(lengthBuf[0]) + hostBuf := make([]byte, l) + if _, err := io.ReadFull(r, hostBuf); err != nil { + return "", err + } + var portBuf [2]byte + if _, err := io.ReadFull(r, portBuf[:]); err != nil { + return "", err + } + return net.JoinHostPort(string(hostBuf), fmt.Sprint(binary.BigEndian.Uint16(portBuf[:]))), nil + default: + return "", fmt.Errorf("unknown address type: %d", atyp[0]) + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/features_test.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/features_test.go new file mode 100644 index 0000000000..8eb3aedd25 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/features_test.go @@ -0,0 +1,192 @@ +package sudoku + +import ( + "bytes" + "io" + "net" + "testing" + "time" + + sudokuobfs "github.com/saba-futai/sudoku/pkg/obfs/sudoku" +) + +type discardConn struct{} + +func (discardConn) Read([]byte) (int, error) { return 0, io.EOF } +func (discardConn) Write(p []byte) (int, error) { return len(p), nil } +func (discardConn) Close() error { return nil } +func (discardConn) LocalAddr() net.Addr { return nil } +func (discardConn) RemoteAddr() net.Addr { return nil } +func (discardConn) SetDeadline(time.Time) error { return nil } +func (discardConn) SetReadDeadline(time.Time) error { return nil } +func (discardConn) SetWriteDeadline(time.Time) error { return nil } + +func TestSudokuObfsWriter_ReducesWriteAllocs(t *testing.T) { + table := sudokuobfs.NewTable("alloc-seed", "prefer_ascii") + w := newSudokuObfsWriter(discardConn{}, table, 0, 0) + + payload := bytes.Repeat([]byte{0x42}, 2048) + if _, err := w.Write(payload); err != nil { + t.Fatalf("warmup write: %v", err) + } + + allocs := testing.AllocsPerRun(100, func() { + if _, err := w.Write(payload); err != nil { + t.Fatalf("write: %v", err) + } + }) + if allocs != 0 { + t.Fatalf("expected 0 allocs/run, got %.2f", allocs) + } +} + +func TestHTTPMaskStrategy_WebSocketAndPost(t *testing.T) { + key := "mask-test-key" + target := "1.1.1.1:80" + table := sudokuobfs.NewTable("mask-seed", "prefer_ascii") + + base := DefaultConfig() + base.Key = key + base.AEADMethod = "chacha20-poly1305" + base.Table = table + base.PaddingMin = 0 + base.PaddingMax = 0 + base.EnablePureDownlink = true + base.HandshakeTimeoutSeconds = 5 + base.DisableHTTPMask = false + base.ServerAddress = "example.com:443" + + cases := []string{"post", "websocket"} + for _, strategy := range cases { + t.Run(strategy, func(t *testing.T) { + serverConn, clientConn := net.Pipe() + defer serverConn.Close() + defer clientConn.Close() + + errCh := make(chan error, 1) + go func() { + defer close(errCh) + session, err := ServerHandshake(serverConn, base) + if err != nil { + errCh <- err + return + } + defer session.Conn.Close() + if session.Type != SessionTypeTCP { + errCh <- io.ErrUnexpectedEOF + return + } + if session.Target != target { + errCh <- io.ErrClosedPipe + return + } + _, _ = session.Conn.Write([]byte("ok")) + }() + + cConn, err := ClientHandshakeWithOptions(clientConn, base, ClientHandshakeOptions{HTTPMaskStrategy: strategy}) + if err != nil { + t.Fatalf("client handshake: %v", err) + } + defer cConn.Close() + + addrBuf, err := EncodeAddress(target) + if err != nil { + t.Fatalf("encode addr: %v", err) + } + if _, err := cConn.Write(addrBuf); err != nil { + t.Fatalf("write addr: %v", err) + } + + buf := make([]byte, 2) + if _, err := io.ReadFull(cConn, buf); err != nil { + t.Fatalf("read: %v", err) + } + if string(buf) != "ok" { + t.Fatalf("unexpected payload: %q", buf) + } + + if err := <-errCh; err != nil { + t.Fatalf("server: %v", err) + } + }) + } +} + +func TestCustomTablesRotation_ProbedByServer(t *testing.T) { + key := "rotate-test-key" + target := "8.8.8.8:53" + + t1, err := sudokuobfs.NewTableWithCustom("rotate-seed", "prefer_entropy", "xpxvvpvv") + if err != nil { + t.Fatalf("t1: %v", err) + } + t2, err := sudokuobfs.NewTableWithCustom("rotate-seed", "prefer_entropy", "vxpvxvvp") + if err != nil { + t.Fatalf("t2: %v", err) + } + + serverCfg := DefaultConfig() + serverCfg.Key = key + serverCfg.AEADMethod = "chacha20-poly1305" + serverCfg.Tables = []*sudokuobfs.Table{t1, t2} + serverCfg.PaddingMin = 0 + serverCfg.PaddingMax = 0 + serverCfg.EnablePureDownlink = true + serverCfg.HandshakeTimeoutSeconds = 5 + serverCfg.DisableHTTPMask = true + + clientCfg := DefaultConfig() + *clientCfg = *serverCfg + clientCfg.ServerAddress = "example.com:443" + + for i := 0; i < 10; i++ { + serverConn, clientConn := net.Pipe() + + errCh := make(chan error, 1) + go func() { + defer close(errCh) + defer serverConn.Close() + session, err := ServerHandshake(serverConn, serverCfg) + if err != nil { + errCh <- err + return + } + defer session.Conn.Close() + if session.Type != SessionTypeTCP { + errCh <- io.ErrUnexpectedEOF + return + } + if session.Target != target { + errCh <- io.ErrClosedPipe + return + } + _, _ = session.Conn.Write([]byte{0xaa, 0xbb, 0xcc}) + }() + + cConn, err := ClientHandshake(clientConn, clientCfg) + if err != nil { + t.Fatalf("client handshake: %v", err) + } + + addrBuf, err := EncodeAddress(target) + if err != nil { + t.Fatalf("encode addr: %v", err) + } + if _, err := cConn.Write(addrBuf); err != nil { + t.Fatalf("write addr: %v", err) + } + + buf := make([]byte, 3) + if _, err := io.ReadFull(cConn, buf); err != nil { + t.Fatalf("read: %v", err) + } + if !bytes.Equal(buf, []byte{0xaa, 0xbb, 0xcc}) { + t.Fatalf("payload mismatch: %x", buf) + } + _ = cConn.Close() + + if err := <-errCh; err != nil { + t.Fatalf("server: %v", err) + } + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake.go new file mode 100644 index 0000000000..989d281323 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake.go @@ -0,0 +1,371 @@ +package sudoku + +import ( + "bufio" + "crypto/rand" + "crypto/sha256" + "encoding/binary" + "fmt" + "io" + "net" + "strings" + "time" + + "github.com/saba-futai/sudoku/apis" + "github.com/saba-futai/sudoku/pkg/crypto" + "github.com/saba-futai/sudoku/pkg/obfs/httpmask" + "github.com/saba-futai/sudoku/pkg/obfs/sudoku" + + "github.com/metacubex/mihomo/log" +) + +type ProtocolConfig = apis.ProtocolConfig + +func DefaultConfig() *ProtocolConfig { return apis.DefaultConfig() } + +type SessionType int + +const ( + SessionTypeTCP SessionType = iota + SessionTypeUoT +) + +type ServerSession struct { + Conn net.Conn + Type SessionType + Target string +} + +type bufferedConn struct { + net.Conn + r *bufio.Reader +} + +func (bc *bufferedConn) Read(p []byte) (int, error) { + return bc.r.Read(p) +} + +type preBufferedConn struct { + net.Conn + buf []byte +} + +func (p *preBufferedConn) Read(b []byte) (int, error) { + if len(p.buf) > 0 { + n := copy(b, p.buf) + p.buf = p.buf[n:] + return n, nil + } + if p.Conn == nil { + return 0, io.EOF + } + return p.Conn.Read(b) +} + +type directionalConn struct { + net.Conn + reader io.Reader + writer io.Writer + closers []func() error +} + +func (c *directionalConn) Read(p []byte) (int, error) { + return c.reader.Read(p) +} + +func (c *directionalConn) Write(p []byte) (int, error) { + return c.writer.Write(p) +} + +func (c *directionalConn) Close() error { + var firstErr error + for _, fn := range c.closers { + if fn == nil { + continue + } + if err := fn(); err != nil && firstErr == nil { + firstErr = err + } + } + if err := c.Conn.Close(); err != nil && firstErr == nil { + firstErr = err + } + return firstErr +} + +func absInt64(v int64) int64 { + if v < 0 { + return -v + } + return v +} + +const ( + downlinkModePure byte = 0x01 + downlinkModePacked byte = 0x02 +) + +func downlinkMode(cfg *apis.ProtocolConfig) byte { + if cfg.EnablePureDownlink { + return downlinkModePure + } + return downlinkModePacked +} + +func buildClientObfsConn(raw net.Conn, cfg *apis.ProtocolConfig, table *sudoku.Table) net.Conn { + baseReader := sudoku.NewConn(raw, table, cfg.PaddingMin, cfg.PaddingMax, false) + baseWriter := newSudokuObfsWriter(raw, table, cfg.PaddingMin, cfg.PaddingMax) + if cfg.EnablePureDownlink { + return &directionalConn{ + Conn: raw, + reader: baseReader, + writer: baseWriter, + } + } + packed := sudoku.NewPackedConn(raw, table, cfg.PaddingMin, cfg.PaddingMax) + return &directionalConn{ + Conn: raw, + reader: packed, + writer: baseWriter, + } +} + +func buildServerObfsConn(raw net.Conn, cfg *apis.ProtocolConfig, table *sudoku.Table, record bool) (*sudoku.Conn, net.Conn) { + uplink := sudoku.NewConn(raw, table, cfg.PaddingMin, cfg.PaddingMax, record) + if cfg.EnablePureDownlink { + downlink := &directionalConn{ + Conn: raw, + reader: uplink, + writer: newSudokuObfsWriter(raw, table, cfg.PaddingMin, cfg.PaddingMax), + } + return uplink, downlink + } + packed := sudoku.NewPackedConn(raw, table, cfg.PaddingMin, cfg.PaddingMax) + return uplink, &directionalConn{ + Conn: raw, + reader: uplink, + writer: packed, + closers: []func() error{packed.Flush}, + } +} + +func buildHandshakePayload(key string) [16]byte { + var payload [16]byte + binary.BigEndian.PutUint64(payload[:8], uint64(time.Now().Unix())) + hash := sha256.Sum256([]byte(key)) + copy(payload[8:], hash[:8]) + return payload +} + +func NewTable(key string, tableType string) *sudoku.Table { + table, err := NewTableWithCustom(key, tableType, "") + if err != nil { + panic(fmt.Sprintf("[Sudoku] failed to init tables: %v", err)) + } + return table +} + +func NewTableWithCustom(key string, tableType string, customTable string) (*sudoku.Table, error) { + start := time.Now() + table, err := sudoku.NewTableWithCustom(key, tableType, customTable) + if err != nil { + return nil, err + } + log.Infoln("[Sudoku] Tables initialized (%s, custom=%v) in %v", tableType, customTable != "", time.Since(start)) + return table, nil +} + +func ClientAEADSeed(key string) string { + if recovered, err := crypto.RecoverPublicKey(key); err == nil { + return crypto.EncodePoint(recovered) + } + return key +} + +type ClientHandshakeOptions struct { + // HTTPMaskStrategy controls how the client generates the HTTP mask header when DisableHTTPMask=false. + // Supported: ""/"random" (default), "post", "websocket". + HTTPMaskStrategy string +} + +// ClientHandshake performs the client-side Sudoku handshake (without sending target address). +func ClientHandshake(rawConn net.Conn, cfg *apis.ProtocolConfig) (net.Conn, error) { + return ClientHandshakeWithOptions(rawConn, cfg, ClientHandshakeOptions{}) +} + +// ClientHandshakeWithOptions performs the client-side Sudoku handshake (without sending target address). +func ClientHandshakeWithOptions(rawConn net.Conn, cfg *apis.ProtocolConfig, opt ClientHandshakeOptions) (net.Conn, error) { + if cfg == nil { + return nil, fmt.Errorf("config is required") + } + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("invalid config: %w", err) + } + + if !cfg.DisableHTTPMask { + if err := WriteHTTPMaskHeader(rawConn, cfg.ServerAddress, opt.HTTPMaskStrategy); err != nil { + return nil, fmt.Errorf("write http mask failed: %w", err) + } + } + + table, tableID, err := pickClientTable(cfg) + if err != nil { + return nil, err + } + + obfsConn := buildClientObfsConn(rawConn, cfg, table) + cConn, err := crypto.NewAEADConn(obfsConn, ClientAEADSeed(cfg.Key), cfg.AEADMethod) + if err != nil { + return nil, fmt.Errorf("setup crypto failed: %w", err) + } + + handshake := buildHandshakePayload(cfg.Key) + if len(tableCandidates(cfg)) > 1 { + handshake[15] = tableID + } + if _, err := cConn.Write(handshake[:]); err != nil { + cConn.Close() + return nil, fmt.Errorf("send handshake failed: %w", err) + } + if _, err := cConn.Write([]byte{downlinkMode(cfg)}); err != nil { + cConn.Close() + return nil, fmt.Errorf("send downlink mode failed: %w", err) + } + + return cConn, nil +} + +// ServerHandshake performs Sudoku server-side handshake and detects UoT preface. +func ServerHandshake(rawConn net.Conn, cfg *apis.ProtocolConfig) (*ServerSession, error) { + if cfg == nil { + return nil, fmt.Errorf("config is required") + } + if err := cfg.Validate(); err != nil { + return nil, fmt.Errorf("invalid config: %w", err) + } + + handshakeTimeout := time.Duration(cfg.HandshakeTimeoutSeconds) * time.Second + if handshakeTimeout <= 0 { + handshakeTimeout = 5 * time.Second + } + + rawConn.SetReadDeadline(time.Now().Add(handshakeTimeout)) + + bufReader := bufio.NewReader(rawConn) + if !cfg.DisableHTTPMask { + if peek, err := bufReader.Peek(4); err == nil && httpmask.LooksLikeHTTPRequestStart(peek) { + if _, err := httpmask.ConsumeHeader(bufReader); err != nil { + return nil, fmt.Errorf("invalid http header: %w", err) + } + } + } + + selectedTable, preRead, err := selectTableByProbe(bufReader, cfg, tableCandidates(cfg)) + if err != nil { + return nil, err + } + + baseConn := &preBufferedConn{Conn: rawConn, buf: preRead} + bConn := &bufferedConn{Conn: baseConn, r: bufio.NewReader(baseConn)} + sConn, obfsConn := buildServerObfsConn(bConn, cfg, selectedTable, true) + cConn, err := crypto.NewAEADConn(obfsConn, cfg.Key, cfg.AEADMethod) + if err != nil { + return nil, fmt.Errorf("crypto setup failed: %w", err) + } + + var handshakeBuf [16]byte + if _, err := io.ReadFull(cConn, handshakeBuf[:]); err != nil { + cConn.Close() + return nil, fmt.Errorf("read handshake failed: %w", err) + } + + ts := int64(binary.BigEndian.Uint64(handshakeBuf[:8])) + if absInt64(time.Now().Unix()-ts) > 60 { + cConn.Close() + return nil, fmt.Errorf("timestamp skew detected") + } + + sConn.StopRecording() + + modeBuf := []byte{0} + if _, err := io.ReadFull(cConn, modeBuf); err != nil { + cConn.Close() + return nil, fmt.Errorf("read downlink mode failed: %w", err) + } + if modeBuf[0] != downlinkMode(cfg) { + cConn.Close() + return nil, fmt.Errorf("downlink mode mismatch: client=%d server=%d", modeBuf[0], downlinkMode(cfg)) + } + + firstByte := make([]byte, 1) + if _, err := io.ReadFull(cConn, firstByte); err != nil { + cConn.Close() + return nil, fmt.Errorf("read first byte failed: %w", err) + } + + if firstByte[0] == UoTMagicByte { + version := make([]byte, 1) + if _, err := io.ReadFull(cConn, version); err != nil { + cConn.Close() + return nil, fmt.Errorf("read uot version failed: %w", err) + } + if version[0] != uotVersion { + cConn.Close() + return nil, fmt.Errorf("unsupported uot version: %d", version[0]) + } + rawConn.SetReadDeadline(time.Time{}) + return &ServerSession{Conn: cConn, Type: SessionTypeUoT}, nil + } + + prefixed := &preBufferedConn{Conn: cConn, buf: firstByte} + target, err := DecodeAddress(prefixed) + if err != nil { + cConn.Close() + return nil, fmt.Errorf("read target address failed: %w", err) + } + + rawConn.SetReadDeadline(time.Time{}) + log.Debugln("[Sudoku] incoming TCP session target: %s", target) + return &ServerSession{ + Conn: prefixed, + Type: SessionTypeTCP, + Target: target, + }, nil +} + +func GenKeyPair() (privateKey, publicKey string, err error) { + // Generate Master Key + pair, err := crypto.GenerateMasterKey() + if err != nil { + return + } + // Split the master private key to get Available Private Key + availablePrivateKey, err := crypto.SplitPrivateKey(pair.Private) + if err != nil { + return + } + privateKey = availablePrivateKey // Available Private Key for client + publicKey = crypto.EncodePoint(pair.Public) // Master Public Key for server + return +} + +func normalizeHTTPMaskStrategy(strategy string) string { + s := strings.TrimSpace(strings.ToLower(strategy)) + switch s { + case "", "random": + return "random" + case "ws": + return "websocket" + default: + return s + } +} + +// randomByte returns a cryptographically random byte (with a math/rand fallback). +func randomByte() byte { + var b [1]byte + if _, err := rand.Read(b[:]); err == nil { + return b[0] + } + return byte(time.Now().UnixNano()) +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake_test.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake_test.go new file mode 100644 index 0000000000..5d9443dfde --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/handshake_test.go @@ -0,0 +1,249 @@ +package sudoku + +import ( + "bytes" + "fmt" + "io" + "net" + "sync" + "testing" + "time" + + "github.com/saba-futai/sudoku/apis" + sudokuobfs "github.com/saba-futai/sudoku/pkg/obfs/sudoku" +) + +func TestPackedConnRoundTrip_WithPadding(t *testing.T) { + payload := []byte{0x3a, 0x1f, 0x71, 0x00, 0xff, 0x10, 0x22} + tableTypes := []string{"prefer_ascii", "prefer_entropy"} + + for _, tt := range tableTypes { + t.Run(tt, func(t *testing.T) { + serverConn, clientConn := net.Pipe() + defer serverConn.Close() + defer clientConn.Close() + + table := sudokuobfs.NewTable("roundtrip-seed", tt) + writer := sudokuobfs.NewPackedConn(serverConn, table, 30, 80) + reader := sudokuobfs.NewPackedConn(clientConn, table, 30, 80) + + writeErr := make(chan error, 1) + go func() { + if _, err := writer.Write(payload); err != nil { + writeErr <- err + return + } + if err := writer.Flush(); err != nil { + writeErr <- err + return + } + writeErr <- serverConn.Close() + }() + + done := make(chan struct{}) + var got []byte + var readErr error + go func() { + got, readErr = io.ReadAll(reader) + close(done) + }() + + select { + case <-done: + case <-time.After(5 * time.Second): + t.Fatal("read timeout") + } + + if err := <-writeErr; err != nil && err != io.EOF { + t.Fatalf("write side error: %v", err) + } + if readErr != nil && readErr != io.EOF { + t.Fatalf("read side error: %v", readErr) + } + if !bytes.Equal(got, payload) { + t.Fatalf("payload mismatch, want %x got %x", payload, got) + } + }) + } +} + +func newPackedConfig(table *sudokuobfs.Table) *apis.ProtocolConfig { + cfg := apis.DefaultConfig() + cfg.Key = "sudoku-test-key" + cfg.Table = table + cfg.PaddingMin = 10 + cfg.PaddingMax = 30 + cfg.EnablePureDownlink = false + cfg.ServerAddress = "example.com:443" + cfg.DisableHTTPMask = true + return cfg +} + +func TestPackedDownlinkSoak(t *testing.T) { + const sessions = 16 + + table := sudokuobfs.NewTable("soak-seed", "prefer_ascii") + cfg := newPackedConfig(table) + + var wg sync.WaitGroup + errCh := make(chan error, sessions*2) + + for i := 0; i < sessions; i++ { + wg.Add(2) + go func(id int) { + defer wg.Done() + runPackedTCPSession(id, cfg, errCh) + }(i) + go func(id int) { + defer wg.Done() + runPackedUoTSession(id, cfg, errCh) + }(i) + } + + done := make(chan struct{}) + go func() { + wg.Wait() + close(done) + }() + + select { + case <-done: + case <-time.After(10 * time.Second): + t.Fatal("soak test timeout") + } + + close(errCh) + for err := range errCh { + t.Fatalf("soak error: %v", err) + } +} + +func runPackedTCPSession(id int, cfg *apis.ProtocolConfig, errCh chan<- error) { + serverConn, clientConn := net.Pipe() + target := fmt.Sprintf("1.1.1.%d:80", (id%200)+1) + payload := []byte{0x42, byte(id)} + + // Server side + go func() { + session, err := ServerHandshake(serverConn, cfg) + if err != nil { + errCh <- fmt.Errorf("server handshake tcp: %w", err) + return + } + defer session.Conn.Close() + + if session.Type != SessionTypeTCP { + errCh <- fmt.Errorf("unexpected session type: %v", session.Type) + return + } + if session.Target != target { + errCh <- fmt.Errorf("target mismatch want %s got %s", target, session.Target) + return + } + if _, err := session.Conn.Write(payload); err != nil { + errCh <- fmt.Errorf("server write: %w", err) + return + } + }() + + // Client side + clientCfg := *cfg + cConn, err := ClientHandshake(clientConn, &clientCfg) + if err != nil { + errCh <- fmt.Errorf("client handshake tcp: %w", err) + return + } + defer cConn.Close() + + addrBuf, err := EncodeAddress(target) + if err != nil { + errCh <- fmt.Errorf("encode address: %w", err) + return + } + if _, err := cConn.Write(addrBuf); err != nil { + errCh <- fmt.Errorf("client send addr: %w", err) + return + } + + buf := make([]byte, len(payload)) + if _, err := io.ReadFull(cConn, buf); err != nil { + errCh <- fmt.Errorf("client read: %w", err) + return + } + if !bytes.Equal(buf, payload) { + errCh <- fmt.Errorf("payload mismatch want %x got %x", payload, buf) + return + } +} + +func runPackedUoTSession(id int, cfg *apis.ProtocolConfig, errCh chan<- error) { + serverConn, clientConn := net.Pipe() + target := "8.8.8.8:53" + payload := []byte{0xaa, byte(id)} + + // Server side + go func() { + session, err := ServerHandshake(serverConn, cfg) + if err != nil { + errCh <- fmt.Errorf("server handshake uot: %w", err) + return + } + defer session.Conn.Close() + + if session.Type != SessionTypeUoT { + errCh <- fmt.Errorf("unexpected session type: %v", session.Type) + return + } + if err := WriteDatagram(session.Conn, target, payload); err != nil { + errCh <- fmt.Errorf("server write datagram: %w", err) + return + } + }() + + // Client side + clientCfg := *cfg + cConn, err := ClientHandshake(clientConn, &clientCfg) + if err != nil { + errCh <- fmt.Errorf("client handshake uot: %w", err) + return + } + defer cConn.Close() + + if err := WritePreface(cConn); err != nil { + errCh <- fmt.Errorf("client write preface: %w", err) + return + } + + addr, data, err := ReadDatagram(cConn) + if err != nil { + errCh <- fmt.Errorf("client read datagram: %w", err) + return + } + if addr != target { + errCh <- fmt.Errorf("uot target mismatch want %s got %s", target, addr) + return + } + if !bytes.Equal(data, payload) { + errCh <- fmt.Errorf("uot payload mismatch want %x got %x", payload, data) + return + } +} + +func TestCustomTableHandshake(t *testing.T) { + table, err := sudokuobfs.NewTableWithCustom("custom-seed", "prefer_entropy", "xpxvvpvv") + if err != nil { + t.Fatalf("build custom table: %v", err) + } + cfg := newPackedConfig(table) + errCh := make(chan error, 2) + + runPackedTCPSession(42, cfg, errCh) + runPackedUoTSession(43, cfg, errCh) + + close(errCh) + for err := range errCh { + if err != nil { + t.Fatalf("custom table handshake failed: %v", err) + } + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_strategy.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_strategy.go new file mode 100644 index 0000000000..dc90991d13 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/httpmask_strategy.go @@ -0,0 +1,179 @@ +package sudoku + +import ( + "encoding/base64" + "fmt" + "io" + "math/rand" + "net" + "strconv" + "sync" + "time" + + "github.com/saba-futai/sudoku/pkg/obfs/httpmask" +) + +var ( + httpMaskUserAgents = []string{ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15", + "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", + } + httpMaskAccepts = []string{ + "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + "application/json, text/plain, */*", + "application/octet-stream", + "*/*", + } + httpMaskAcceptLanguages = []string{ + "en-US,en;q=0.9", + "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7", + } + httpMaskAcceptEncodings = []string{ + "gzip, deflate, br", + "gzip, deflate", + } + httpMaskPaths = []string{ + "/api/v1/upload", + "/data/sync", + "/v1/telemetry", + "/session", + "/ws", + } + httpMaskContentTypes = []string{ + "application/octet-stream", + "application/json", + } +) + +var ( + httpMaskRngPool = sync.Pool{ + New: func() any { return rand.New(rand.NewSource(time.Now().UnixNano())) }, + } + httpMaskBufPool = sync.Pool{ + New: func() any { + b := make([]byte, 0, 1024) + return &b + }, + } +) + +func trimPortForHost(host string) string { + if host == "" { + return host + } + h, _, err := net.SplitHostPort(host) + if err == nil && h != "" { + return h + } + return host +} + +func appendCommonHeaders(buf []byte, host string, r *rand.Rand) []byte { + ua := httpMaskUserAgents[r.Intn(len(httpMaskUserAgents))] + accept := httpMaskAccepts[r.Intn(len(httpMaskAccepts))] + lang := httpMaskAcceptLanguages[r.Intn(len(httpMaskAcceptLanguages))] + enc := httpMaskAcceptEncodings[r.Intn(len(httpMaskAcceptEncodings))] + + buf = append(buf, "Host: "...) + buf = append(buf, host...) + buf = append(buf, "\r\nUser-Agent: "...) + buf = append(buf, ua...) + buf = append(buf, "\r\nAccept: "...) + buf = append(buf, accept...) + buf = append(buf, "\r\nAccept-Language: "...) + buf = append(buf, lang...) + buf = append(buf, "\r\nAccept-Encoding: "...) + buf = append(buf, enc...) + buf = append(buf, "\r\nConnection: keep-alive\r\n"...) + buf = append(buf, "Cache-Control: no-cache\r\nPragma: no-cache\r\n"...) + return buf +} + +// WriteHTTPMaskHeader writes an HTTP/1.x request header as a mask, according to strategy. +// Supported strategies: ""/"random", "post", "websocket". +func WriteHTTPMaskHeader(w io.Writer, host string, strategy string) error { + switch normalizeHTTPMaskStrategy(strategy) { + case "random": + return httpmask.WriteRandomRequestHeader(w, host) + case "post": + return writeHTTPMaskPOST(w, host) + case "websocket": + return writeHTTPMaskWebSocket(w, host) + default: + return fmt.Errorf("unsupported http-mask-strategy: %s", strategy) + } +} + +func writeHTTPMaskPOST(w io.Writer, host string) error { + r := httpMaskRngPool.Get().(*rand.Rand) + defer httpMaskRngPool.Put(r) + + path := httpMaskPaths[r.Intn(len(httpMaskPaths))] + ctype := httpMaskContentTypes[r.Intn(len(httpMaskContentTypes))] + + bufPtr := httpMaskBufPool.Get().(*[]byte) + buf := *bufPtr + buf = buf[:0] + defer func() { + if cap(buf) <= 4096 { + *bufPtr = buf + httpMaskBufPool.Put(bufPtr) + } + }() + + const minCL = int64(4 * 1024) + const maxCL = int64(10 * 1024 * 1024) + contentLength := minCL + r.Int63n(maxCL-minCL+1) + + buf = append(buf, "POST "...) + buf = append(buf, path...) + buf = append(buf, " HTTP/1.1\r\n"...) + buf = appendCommonHeaders(buf, host, r) + buf = append(buf, "Content-Type: "...) + buf = append(buf, ctype...) + buf = append(buf, "\r\nContent-Length: "...) + buf = strconv.AppendInt(buf, contentLength, 10) + buf = append(buf, "\r\n\r\n"...) + + _, err := w.Write(buf) + return err +} + +func writeHTTPMaskWebSocket(w io.Writer, host string) error { + r := httpMaskRngPool.Get().(*rand.Rand) + defer httpMaskRngPool.Put(r) + + path := httpMaskPaths[r.Intn(len(httpMaskPaths))] + + bufPtr := httpMaskBufPool.Get().(*[]byte) + buf := *bufPtr + buf = buf[:0] + defer func() { + if cap(buf) <= 4096 { + *bufPtr = buf + httpMaskBufPool.Put(bufPtr) + } + }() + + hostNoPort := trimPortForHost(host) + var keyBytes [16]byte + for i := 0; i < len(keyBytes); i++ { + keyBytes[i] = byte(r.Intn(256)) + } + var wsKey [24]byte + base64.StdEncoding.Encode(wsKey[:], keyBytes[:]) + + buf = append(buf, "GET "...) + buf = append(buf, path...) + buf = append(buf, " HTTP/1.1\r\n"...) + buf = appendCommonHeaders(buf, host, r) + buf = append(buf, "Upgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: "...) + buf = append(buf, wsKey[:]...) + buf = append(buf, "\r\nOrigin: https://"...) + buf = append(buf, hostNoPort...) + buf = append(buf, "\r\n\r\n"...) + + _, err := w.Write(buf) + return err +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs_writer.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs_writer.go new file mode 100644 index 0000000000..f980359119 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/obfs_writer.go @@ -0,0 +1,113 @@ +package sudoku + +import ( + crypto_rand "crypto/rand" + "encoding/binary" + "math/rand" + "net" + + "github.com/saba-futai/sudoku/pkg/obfs/sudoku" +) + +// perm4 matches github.com/saba-futai/sudoku/pkg/obfs/sudoku perm4. +var perm4 = [24][4]byte{ + {0, 1, 2, 3}, + {0, 1, 3, 2}, + {0, 2, 1, 3}, + {0, 2, 3, 1}, + {0, 3, 1, 2}, + {0, 3, 2, 1}, + {1, 0, 2, 3}, + {1, 0, 3, 2}, + {1, 2, 0, 3}, + {1, 2, 3, 0}, + {1, 3, 0, 2}, + {1, 3, 2, 0}, + {2, 0, 1, 3}, + {2, 0, 3, 1}, + {2, 1, 0, 3}, + {2, 1, 3, 0}, + {2, 3, 0, 1}, + {2, 3, 1, 0}, + {3, 0, 1, 2}, + {3, 0, 2, 1}, + {3, 1, 0, 2}, + {3, 1, 2, 0}, + {3, 2, 0, 1}, + {3, 2, 1, 0}, +} + +type sudokuObfsWriter struct { + conn net.Conn + table *sudoku.Table + rng *rand.Rand + paddingRate float32 + + outBuf []byte + pads []byte + padLen int +} + +func newSudokuObfsWriter(conn net.Conn, table *sudoku.Table, pMin, pMax int) *sudokuObfsWriter { + var seedBytes [8]byte + if _, err := crypto_rand.Read(seedBytes[:]); err != nil { + binary.BigEndian.PutUint64(seedBytes[:], uint64(rand.Int63())) + } + seed := int64(binary.BigEndian.Uint64(seedBytes[:])) + localRng := rand.New(rand.NewSource(seed)) + + min := float32(pMin) / 100.0 + span := float32(pMax-pMin) / 100.0 + rate := min + localRng.Float32()*span + + w := &sudokuObfsWriter{ + conn: conn, + table: table, + rng: localRng, + paddingRate: rate, + } + w.pads = table.PaddingPool + w.padLen = len(w.pads) + return w +} + +func (w *sudokuObfsWriter) Write(p []byte) (int, error) { + if len(p) == 0 { + return 0, nil + } + + // Worst-case: 4 hints + up to 6 paddings per input byte. + needed := len(p)*10 + 1 + if cap(w.outBuf) < needed { + w.outBuf = make([]byte, 0, needed) + } + out := w.outBuf[:0] + + pads := w.pads + padLen := w.padLen + + for _, b := range p { + if padLen > 0 && w.rng.Float32() < w.paddingRate { + out = append(out, pads[w.rng.Intn(padLen)]) + } + + puzzles := w.table.EncodeTable[b] + puzzle := puzzles[w.rng.Intn(len(puzzles))] + + perm := perm4[w.rng.Intn(len(perm4))] + for _, idx := range perm { + if padLen > 0 && w.rng.Float32() < w.paddingRate { + out = append(out, pads[w.rng.Intn(padLen)]) + } + out = append(out, puzzle[idx]) + } + } + + if padLen > 0 && w.rng.Float32() < w.paddingRate { + out = append(out, pads[w.rng.Intn(padLen)]) + } + + w.outBuf = out + _, err := w.conn.Write(out) + return len(p), err +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/table_probe.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/table_probe.go new file mode 100644 index 0000000000..f12c172226 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/table_probe.go @@ -0,0 +1,152 @@ +package sudoku + +import ( + "bufio" + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "net" + "time" + + "github.com/saba-futai/sudoku/apis" + "github.com/saba-futai/sudoku/pkg/crypto" + "github.com/saba-futai/sudoku/pkg/obfs/sudoku" +) + +func tableCandidates(cfg *apis.ProtocolConfig) []*sudoku.Table { + if cfg == nil { + return nil + } + if len(cfg.Tables) > 0 { + return cfg.Tables + } + if cfg.Table != nil { + return []*sudoku.Table{cfg.Table} + } + return nil +} + +func pickClientTable(cfg *apis.ProtocolConfig) (*sudoku.Table, byte, error) { + candidates := tableCandidates(cfg) + if len(candidates) == 0 { + return nil, 0, fmt.Errorf("no table configured") + } + if len(candidates) == 1 { + return candidates[0], 0, nil + } + idx := int(randomByte()) % len(candidates) + return candidates[idx], byte(idx), nil +} + +type readOnlyConn struct { + *bytes.Reader +} + +func (c *readOnlyConn) Write([]byte) (int, error) { return 0, io.ErrClosedPipe } +func (c *readOnlyConn) Close() error { return nil } +func (c *readOnlyConn) LocalAddr() net.Addr { return nil } +func (c *readOnlyConn) RemoteAddr() net.Addr { return nil } +func (c *readOnlyConn) SetDeadline(time.Time) error { return nil } +func (c *readOnlyConn) SetReadDeadline(time.Time) error { return nil } +func (c *readOnlyConn) SetWriteDeadline(time.Time) error { return nil } + +func drainBuffered(r *bufio.Reader) ([]byte, error) { + n := r.Buffered() + if n <= 0 { + return nil, nil + } + out := make([]byte, n) + _, err := io.ReadFull(r, out) + return out, err +} + +func probeHandshakeBytes(probe []byte, cfg *apis.ProtocolConfig, table *sudoku.Table) error { + rc := &readOnlyConn{Reader: bytes.NewReader(probe)} + _, obfsConn := buildServerObfsConn(rc, cfg, table, false) + cConn, err := crypto.NewAEADConn(obfsConn, cfg.Key, cfg.AEADMethod) + if err != nil { + return err + } + + var handshakeBuf [16]byte + if _, err := io.ReadFull(cConn, handshakeBuf[:]); err != nil { + return err + } + ts := int64(binary.BigEndian.Uint64(handshakeBuf[:8])) + if absInt64(time.Now().Unix()-ts) > 60 { + return fmt.Errorf("timestamp skew/replay detected") + } + + modeBuf := []byte{0} + if _, err := io.ReadFull(cConn, modeBuf); err != nil { + return err + } + if modeBuf[0] != downlinkMode(cfg) { + return fmt.Errorf("downlink mode mismatch") + } + + return nil +} + +func selectTableByProbe(r *bufio.Reader, cfg *apis.ProtocolConfig, tables []*sudoku.Table) (*sudoku.Table, []byte, error) { + const ( + maxProbeBytes = 64 * 1024 + readChunk = 4 * 1024 + ) + if len(tables) == 0 { + return nil, nil, fmt.Errorf("no table candidates") + } + if len(tables) > 255 { + return nil, nil, fmt.Errorf("too many table candidates: %d", len(tables)) + } + + probe, err := drainBuffered(r) + if err != nil { + return nil, nil, fmt.Errorf("drain buffered bytes failed: %w", err) + } + + tmp := make([]byte, readChunk) + for { + if len(tables) == 1 { + tail, err := drainBuffered(r) + if err != nil { + return nil, nil, fmt.Errorf("drain buffered bytes failed: %w", err) + } + probe = append(probe, tail...) + return tables[0], probe, nil + } + + needMore := false + for _, table := range tables { + err := probeHandshakeBytes(probe, cfg, table) + if err == nil { + tail, err := drainBuffered(r) + if err != nil { + return nil, nil, fmt.Errorf("drain buffered bytes failed: %w", err) + } + probe = append(probe, tail...) + return table, probe, nil + } + if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { + needMore = true + } + } + + if !needMore { + return nil, probe, fmt.Errorf("handshake table selection failed") + } + if len(probe) >= maxProbeBytes { + return nil, probe, fmt.Errorf("handshake probe exceeded %d bytes", maxProbeBytes) + } + + n, err := r.Read(tmp) + if n > 0 { + probe = append(probe, tmp[:n]...) + } + if err != nil { + return nil, probe, fmt.Errorf("handshake probe read failed: %w", err) + } + } +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/tables.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/tables.go new file mode 100644 index 0000000000..429a4ab327 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/tables.go @@ -0,0 +1,30 @@ +package sudoku + +import ( + "strings" + + "github.com/saba-futai/sudoku/pkg/obfs/sudoku" +) + +// NewTablesWithCustomPatterns builds one or more obfuscation tables from x/v/p custom patterns. +// When customTables is non-empty it overrides customTable (matching upstream Sudoku behavior). +func NewTablesWithCustomPatterns(key string, tableType string, customTable string, customTables []string) ([]*sudoku.Table, error) { + patterns := customTables + if len(patterns) == 0 && strings.TrimSpace(customTable) != "" { + patterns = []string{customTable} + } + if len(patterns) == 0 { + patterns = []string{""} + } + + tables := make([]*sudoku.Table, 0, len(patterns)) + for _, pattern := range patterns { + pattern = strings.TrimSpace(pattern) + t, err := NewTableWithCustom(key, tableType, pattern) + if err != nil { + return nil, err + } + tables = append(tables, t) + } + return tables, nil +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/uot.go b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/uot.go new file mode 100644 index 0000000000..be3fe90033 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/transport/sudoku/uot.go @@ -0,0 +1,158 @@ +package sudoku + +import ( + "bytes" + "encoding/binary" + "errors" + "fmt" + "io" + "net" + "net/netip" + "strconv" + "sync" + "time" + + "github.com/metacubex/mihomo/log" +) + +const ( + UoTMagicByte byte = 0xEE + uotVersion = 0x01 + maxUoTPayload = 64 * 1024 +) + +// WritePreface writes the UDP-over-TCP marker and version. +func WritePreface(w io.Writer) error { + _, err := w.Write([]byte{UoTMagicByte, uotVersion}) + return err +} + +// WriteDatagram sends a single UDP datagram frame over a reliable stream. +func WriteDatagram(w io.Writer, addr string, payload []byte) error { + addrBuf, err := EncodeAddress(addr) + if err != nil { + return fmt.Errorf("encode address: %w", err) + } + + if addrLen := len(addrBuf); addrLen == 0 || addrLen > maxUoTPayload { + return fmt.Errorf("address too long: %d", len(addrBuf)) + } + if payloadLen := len(payload); payloadLen > maxUoTPayload { + return fmt.Errorf("payload too large: %d", payloadLen) + } + + var header [4]byte + binary.BigEndian.PutUint16(header[:2], uint16(len(addrBuf))) + binary.BigEndian.PutUint16(header[2:], uint16(len(payload))) + + if _, err := w.Write(header[:]); err != nil { + return err + } + if _, err := w.Write(addrBuf); err != nil { + return err + } + _, err = w.Write(payload) + return err +} + +// ReadDatagram parses a single UDP datagram frame from the reliable stream. +func ReadDatagram(r io.Reader) (string, []byte, error) { + var header [4]byte + if _, err := io.ReadFull(r, header[:]); err != nil { + return "", nil, err + } + + addrLen := int(binary.BigEndian.Uint16(header[:2])) + payloadLen := int(binary.BigEndian.Uint16(header[2:])) + + if addrLen <= 0 || addrLen > maxUoTPayload { + return "", nil, fmt.Errorf("invalid address length: %d", addrLen) + } + if payloadLen < 0 || payloadLen > maxUoTPayload { + return "", nil, fmt.Errorf("invalid payload length: %d", payloadLen) + } + + addrBuf := make([]byte, addrLen) + if _, err := io.ReadFull(r, addrBuf); err != nil { + return "", nil, err + } + + addr, err := DecodeAddress(bytes.NewReader(addrBuf)) + if err != nil { + return "", nil, fmt.Errorf("decode address: %w", err) + } + + payload := make([]byte, payloadLen) + if _, err := io.ReadFull(r, payload); err != nil { + return "", nil, err + } + + return addr, payload, nil +} + +// UoTPacketConn adapts a net.Conn with the Sudoku UoT framing to net.PacketConn. +type UoTPacketConn struct { + conn net.Conn + writeMu sync.Mutex +} + +func NewUoTPacketConn(conn net.Conn) *UoTPacketConn { + return &UoTPacketConn{conn: conn} +} + +func (c *UoTPacketConn) ReadFrom(p []byte) (int, net.Addr, error) { + for { + addrStr, payload, err := ReadDatagram(c.conn) + if err != nil { + return 0, nil, err + } + + if len(payload) > len(p) { + return 0, nil, io.ErrShortBuffer + } + + host, port, _ := net.SplitHostPort(addrStr) + portInt, _ := strconv.ParseUint(port, 10, 16) + ip, err := netip.ParseAddr(host) + if err != nil { // disallow domain addr at here, just ignore + log.Debugln("[Sudoku][UoT] discard datagram with invalid address %s: %v", addrStr, err) + continue + } + udpAddr := net.UDPAddrFromAddrPort(netip.AddrPortFrom(ip.Unmap(), uint16(portInt))) + + copy(p, payload) + return len(payload), udpAddr, nil + } +} + +func (c *UoTPacketConn) WriteTo(p []byte, addr net.Addr) (int, error) { + if addr == nil { + return 0, errors.New("address is nil") + } + c.writeMu.Lock() + defer c.writeMu.Unlock() + if err := WriteDatagram(c.conn, addr.String(), p); err != nil { + return 0, err + } + return len(p), nil +} + +func (c *UoTPacketConn) Close() error { + return c.conn.Close() +} + +func (c *UoTPacketConn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +func (c *UoTPacketConn) SetDeadline(t time.Time) error { + return c.conn.SetDeadline(t) +} + +func (c *UoTPacketConn) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} + +func (c *UoTPacketConn) SetWriteDeadline(t time.Time) error { + return c.conn.SetWriteDeadline(t) +} diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/common/type.go b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/common/type.go index c663fa0b9e..0110fd7232 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/common/type.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/common/type.go @@ -18,13 +18,12 @@ var ( TooManyOpenStreams = errors.New("tuic: too many open streams") ) -type DialFunc func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) +type DialFunc func(ctx context.Context) (transport *quic.Transport, addr net.Addr, err error) type Client interface { - DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.Conn, error) - ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) + DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) + ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) OpenStreams() int64 - DialerRef() C.Dialer LastVisited() time.Time SetLastVisited(last time.Time) Close() diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/pool_client.go b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/pool_client.go index b4c319d819..ab65c14db5 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/pool_client.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/pool_client.go @@ -6,6 +6,7 @@ import ( "net" "runtime" "sync" + "sync/atomic" "time" N "github.com/metacubex/mihomo/common/net" @@ -17,30 +18,21 @@ import ( list "github.com/bahlo/generic-list-go" ) -type dialResult struct { - transport *quic.Transport - addr net.Addr - err error -} - type PoolClient struct { newClientOptionV4 *ClientOptionV4 newClientOptionV5 *ClientOptionV5 - dialResultMap map[C.Dialer]dialResult - dialResultMutex *sync.Mutex - tcpClients *list.List[Client] - tcpClientsMutex *sync.Mutex - udpClients *list.List[Client] - udpClientsMutex *sync.Mutex + + dialHelper *poolDialHelper + tcpClients list.List[Client] + tcpClientsMutex sync.Mutex + udpClients list.List[Client] + udpClientsMutex sync.Mutex } -func (t *PoolClient) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.Conn, error) { - newDialFn := func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) { - return t.dial(ctx, dialer, dialFn) - } - conn, err := t.getClient(false, dialer).DialContextWithDialer(ctx, metadata, dialer, newDialFn) +func (t *PoolClient) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) { + conn, err := t.getClient(false).DialContext(ctx, metadata) if errors.Is(err, TooManyOpenStreams) { - conn, err = t.newClient(false, dialer).DialContextWithDialer(ctx, metadata, dialer, newDialFn) + conn, err = t.newClient(false).DialContext(ctx, metadata) } if err != nil { return nil, err @@ -48,13 +40,10 @@ func (t *PoolClient) DialContextWithDialer(ctx context.Context, metadata *C.Meta return N.NewRefConn(conn, t), err } -func (t *PoolClient) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) { - newDialFn := func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) { - return t.dial(ctx, dialer, dialFn) - } - pc, err := t.getClient(true, dialer).ListenPacketWithDialer(ctx, metadata, dialer, newDialFn) +func (t *PoolClient) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) { + pc, err := t.getClient(true).ListenPacket(ctx, metadata) if errors.Is(err, TooManyOpenStreams) { - pc, err = t.newClient(true, dialer).ListenPacketWithDialer(ctx, metadata, dialer, newDialFn) + pc, err = t.newClient(true).ListenPacket(ctx, metadata) } if err != nil { return nil, err @@ -62,58 +51,63 @@ func (t *PoolClient) ListenPacketWithDialer(ctx context.Context, metadata *C.Met return N.NewRefPacketConn(pc, t), nil } -func (t *PoolClient) dial(ctx context.Context, dialer C.Dialer, dialFn DialFunc) (transport *quic.Transport, addr net.Addr, err error) { - t.dialResultMutex.Lock() - dr, ok := t.dialResultMap[dialer] - t.dialResultMutex.Unlock() - if ok { - return dr.transport, dr.addr, dr.err +// poolDialHelper is a helper for dialFn +// using a standalone struct to let finalizer working +type poolDialHelper struct { + dialFn DialFunc + dialResult atomic.Pointer[dialResult] +} + +type dialResult struct { + transport *quic.Transport + addr net.Addr +} + +func (t *poolDialHelper) dial(ctx context.Context) (transport *quic.Transport, addr net.Addr, err error) { + if dr := t.dialResult.Load(); dr != nil { + return dr.transport, dr.addr, nil } - transport, addr, err = dialFn(ctx, dialer) + transport, addr, err = t.dialFn(ctx) if err != nil { return nil, nil, err } if _, ok := transport.Conn.(*net.UDPConn); ok { // only cache the system's UDPConn transport.SetSingleUse(false) // don't close transport in each dial - dr.transport, dr.addr, dr.err = transport, addr, err - t.dialResultMutex.Lock() - t.dialResultMap[dialer] = dr - t.dialResultMutex.Unlock() + dr := &dialResult{transport: transport, addr: addr} + t.dialResult.Store(dr) } return transport, addr, err } -func (t *PoolClient) forceClose() { - t.dialResultMutex.Lock() - defer t.dialResultMutex.Unlock() - for key := range t.dialResultMap { - transport := t.dialResultMap[key].transport +func (t *poolDialHelper) forceClose() { + if dr := t.dialResult.Swap(nil); dr != nil { + transport := dr.transport if transport != nil { _ = transport.Close() } - delete(t.dialResultMap, key) } } -func (t *PoolClient) newClient(udp bool, dialer C.Dialer) (client Client) { - clients := t.tcpClients - clientsMutex := t.tcpClientsMutex +func (t *PoolClient) newClient(udp bool) (client Client) { + clients := &t.tcpClients + clientsMutex := &t.tcpClientsMutex if udp { - clients = t.udpClients - clientsMutex = t.udpClientsMutex + clients = &t.udpClients + clientsMutex = &t.udpClientsMutex } clientsMutex.Lock() defer clientsMutex.Unlock() + dialHelper := t.dialHelper if t.newClientOptionV4 != nil { - client = NewClientV4(t.newClientOptionV4, udp, dialer) + client = NewClientV4(t.newClientOptionV4, udp, dialHelper.dial) } else { - client = NewClientV5(t.newClientOptionV5, udp, dialer) + client = NewClientV5(t.newClientOptionV5, udp, dialHelper.dial) } client.SetLastVisited(time.Now()) @@ -122,12 +116,12 @@ func (t *PoolClient) newClient(udp bool, dialer C.Dialer) (client Client) { return client } -func (t *PoolClient) getClient(udp bool, dialer C.Dialer) Client { - clients := t.tcpClients - clientsMutex := t.tcpClientsMutex +func (t *PoolClient) getClient(udp bool) Client { + clients := &t.tcpClients + clientsMutex := &t.tcpClientsMutex if udp { - clients = t.udpClients - clientsMutex = t.udpClientsMutex + clients = &t.udpClients + clientsMutex = &t.udpClientsMutex } var bestClient Client @@ -142,46 +136,39 @@ func (t *PoolClient) getClient(udp bool, dialer C.Dialer) Client { it = next continue } - if client.DialerRef() == dialer { - if bestClient == nil { + if bestClient == nil { + bestClient = client + } else { + if client.OpenStreams() < bestClient.OpenStreams() { bestClient = client - } else { - if client.OpenStreams() < bestClient.OpenStreams() { - bestClient = client - } } } it = it.Next() } - }() - for it := clients.Front(); it != nil; { - client := it.Value - if client != bestClient && client.OpenStreams() == 0 && time.Now().Sub(client.LastVisited()) > 30*time.Minute { - client.Close() - next := it.Next() - clients.Remove(it) - it = next - continue + for it := clients.Front(); it != nil; { + client := it.Value + if client != bestClient && client.OpenStreams() == 0 && time.Now().Sub(client.LastVisited()) > 30*time.Minute { + client.Close() + next := it.Next() + clients.Remove(it) + it = next + continue + } + it = it.Next() } - it = it.Next() - } + }() if bestClient == nil { - return t.newClient(udp, dialer) + return t.newClient(udp) } else { bestClient.SetLastVisited(time.Now()) return bestClient } } -func NewPoolClientV4(clientOption *ClientOptionV4) *PoolClient { +func NewPoolClientV4(clientOption *ClientOptionV4, dialFn DialFunc) *PoolClient { p := &PoolClient{ - dialResultMap: make(map[C.Dialer]dialResult), - dialResultMutex: &sync.Mutex{}, - tcpClients: list.New[Client](), - tcpClientsMutex: &sync.Mutex{}, - udpClients: list.New[Client](), - udpClientsMutex: &sync.Mutex{}, + dialHelper: &poolDialHelper{dialFn: dialFn}, } newClientOption := *clientOption p.newClientOptionV4 = &newClientOption @@ -190,14 +177,9 @@ func NewPoolClientV4(clientOption *ClientOptionV4) *PoolClient { return p } -func NewPoolClientV5(clientOption *ClientOptionV5) *PoolClient { +func NewPoolClientV5(clientOption *ClientOptionV5, dialFn DialFunc) *PoolClient { p := &PoolClient{ - dialResultMap: make(map[C.Dialer]dialResult), - dialResultMutex: &sync.Mutex{}, - tcpClients: list.New[Client](), - tcpClientsMutex: &sync.Mutex{}, - udpClients: list.New[Client](), - udpClientsMutex: &sync.Mutex{}, + dialHelper: &poolDialHelper{dialFn: dialFn}, } newClientOption := *clientOption p.newClientOptionV5 = &newClientOption @@ -208,5 +190,5 @@ func NewPoolClientV5(clientOption *ClientOptionV5) *PoolClient { func closeClientPool(client *PoolClient) { log.Debugln("Close Tuic PoolClient at %p", client) - client.forceClose() + client.dialHelper.forceClose() } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/server.go b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/server.go index d9d6439ec1..152c9d1b1c 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/server.go @@ -9,7 +9,6 @@ import ( "github.com/metacubex/mihomo/adapter/inbound" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/utils" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/socks5" "github.com/metacubex/mihomo/transport/tuic/common" @@ -18,13 +17,14 @@ import ( "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" + "github.com/metacubex/tls" ) type ServerOption struct { HandleTcpFn func(conn net.Conn, addr socks5.Addr, additions ...inbound.Addition) error HandleUdpFn func(addr socks5.Addr, packet C.UDPPacket, additions ...inbound.Addition) error - TlsConfig *tlsC.Config + TlsConfig *tls.Config QuicConfig *quic.Config Tokens [][32]byte // V4 special Users map[[16]byte]string // V5 special diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/tuic.go b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/tuic.go index 02aaa3ad36..ae52c07ac6 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/tuic.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/tuic.go @@ -1,7 +1,6 @@ package tuic import ( - C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/tuic/common" v4 "github.com/metacubex/mihomo/transport/tuic/v4" v5 "github.com/metacubex/mihomo/transport/tuic/v5" @@ -12,12 +11,12 @@ type ClientOptionV5 = v5.ClientOption type Client = common.Client -func NewClientV4(clientOption *ClientOptionV4, udp bool, dialerRef C.Dialer) Client { - return v4.NewClient(clientOption, udp, dialerRef) +func NewClientV4(clientOption *ClientOptionV4, udp bool, dialFn DialFunc) Client { + return v4.NewClient(clientOption, udp, dialFn) } -func NewClientV5(clientOption *ClientOptionV5, udp bool, dialerRef C.Dialer) Client { - return v5.NewClient(clientOption, udp, dialerRef) +func NewClientV5(clientOption *ClientOptionV5, udp bool, dialFn DialFunc) Client { + return v5.NewClient(clientOption, udp, dialFn) } type DialFunc = common.DialFunc diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/v4/client.go b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/v4/client.go index 0c57e0df15..b2affe9641 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/v4/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/v4/client.go @@ -15,17 +15,17 @@ import ( N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/pool" "github.com/metacubex/mihomo/common/xsync" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/metacubex/randv2" + "github.com/metacubex/tls" ) type ClientOption struct { - TlsConfig *tlsC.Config + TlsConfig *tls.Config QuicConfig *quic.Config Token [32]byte UdpRelayMode common.UdpRelayMode @@ -40,7 +40,8 @@ type ClientOption struct { type clientImpl struct { *ClientOption - udp bool + dialFn common.DialFunc + udp bool quicConn *quic.Conn connMutex sync.Mutex @@ -51,7 +52,6 @@ type clientImpl struct { udpInputMap xsync.Map[uint32, net.Conn] // only ready for PoolClient - dialerRef C.Dialer lastVisited atomic2.TypedValue[time.Time] } @@ -59,10 +59,6 @@ func (t *clientImpl) OpenStreams() int64 { return t.openStreams.Load() } -func (t *clientImpl) DialerRef() C.Dialer { - return t.dialerRef -} - func (t *clientImpl) LastVisited() time.Time { return t.lastVisited.Load() } @@ -71,13 +67,13 @@ func (t *clientImpl) SetLastVisited(last time.Time) { t.lastVisited.Store(last) } -func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn common.DialFunc) (*quic.Conn, error) { +func (t *clientImpl) getQuicConn(ctx context.Context) (*quic.Conn, error) { t.connMutex.Lock() defer t.connMutex.Unlock() if t.quicConn != nil { return t.quicConn, nil } - transport, addr, err := dialFn(ctx, dialer) + transport, addr, err := t.dialFn(ctx) if err != nil { return nil, err } @@ -262,7 +258,7 @@ func (t *clientImpl) forceClose(quicConn *quic.Conn, err error) { if quicConn != nil { _ = quicConn.CloseWithError(ProtocolError, errStr) } - udpInputMap := t.udpInputMap + udpInputMap := &t.udpInputMap udpInputMap.Range(func(key uint32, value net.Conn) bool { conn := value _ = conn.Close() @@ -278,8 +274,8 @@ func (t *clientImpl) Close() { } } -func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) { - quicConn, err := t.getQuicConn(ctx, dialer, dialFn) +func (t *clientImpl) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) { + quicConn, err := t.getQuicConn(ctx) if err != nil { return nil, err } @@ -353,8 +349,8 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta return bufConn, nil } -func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) { - quicConn, err := t.getQuicConn(ctx, dialer, dialFn) +func (t *clientImpl) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) { + quicConn, err := t.getQuicConn(ctx) if err != nil { return nil, err } @@ -397,16 +393,16 @@ type Client struct { *clientImpl // use an independent pointer to let Finalizer can work no matter somewhere handle an influence in clientImpl inner } -func (t *Client) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) { - conn, err := t.clientImpl.DialContextWithDialer(ctx, metadata, dialer, dialFn) +func (t *Client) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) { + conn, err := t.clientImpl.DialContext(ctx, metadata) if err != nil { return nil, err } return N.NewRefConn(conn, t), err } -func (t *Client) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) { - pc, err := t.clientImpl.ListenPacketWithDialer(ctx, metadata, dialer, dialFn) +func (t *Client) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) { + pc, err := t.clientImpl.ListenPacket(ctx, metadata) if err != nil { return nil, err } @@ -417,11 +413,11 @@ func (t *Client) forceClose() { t.clientImpl.forceClose(nil, common.ClientClosed) } -func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client { +func NewClient(clientOption *ClientOption, udp bool, dialFn common.DialFunc) *Client { ci := &clientImpl{ ClientOption: clientOption, + dialFn: dialFn, udp: udp, - dialerRef: dialerRef, } c := &Client{ci} runtime.SetFinalizer(c, closeClient) diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/v5/client.go b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/v5/client.go index 5fc1388899..77e4f36948 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/tuic/v5/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/tuic/v5/client.go @@ -15,17 +15,17 @@ import ( N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/pool" "github.com/metacubex/mihomo/common/xsync" - tlsC "github.com/metacubex/mihomo/component/tls" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/metacubex/randv2" + "github.com/metacubex/tls" ) type ClientOption struct { - TlsConfig *tlsC.Config + TlsConfig *tls.Config QuicConfig *quic.Config Uuid [16]byte Password string @@ -39,7 +39,8 @@ type ClientOption struct { type clientImpl struct { *ClientOption - udp bool + dialFn common.DialFunc + udp bool quicConn *quic.Conn connMutex sync.Mutex @@ -50,7 +51,6 @@ type clientImpl struct { udpInputMap xsync.Map[uint16, net.Conn] // only ready for PoolClient - dialerRef C.Dialer lastVisited atomic2.TypedValue[time.Time] } @@ -58,10 +58,6 @@ func (t *clientImpl) OpenStreams() int64 { return t.openStreams.Load() } -func (t *clientImpl) DialerRef() C.Dialer { - return t.dialerRef -} - func (t *clientImpl) LastVisited() time.Time { return t.lastVisited.Load() } @@ -70,13 +66,13 @@ func (t *clientImpl) SetLastVisited(last time.Time) { t.lastVisited.Store(last) } -func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn common.DialFunc) (*quic.Conn, error) { +func (t *clientImpl) getQuicConn(ctx context.Context) (*quic.Conn, error) { t.connMutex.Lock() defer t.connMutex.Unlock() if t.quicConn != nil { return t.quicConn, nil } - transport, addr, err := dialFn(ctx, dialer) + transport, addr, err := t.dialFn(ctx) if err != nil { return nil, err } @@ -270,7 +266,7 @@ func (t *clientImpl) forceClose(quicConn *quic.Conn, err error) { if quicConn != nil { _ = quicConn.CloseWithError(ProtocolError, errStr) } - udpInputMap := t.udpInputMap + udpInputMap := &t.udpInputMap udpInputMap.Range(func(key uint16, value net.Conn) bool { conn := value _ = conn.Close() @@ -286,8 +282,8 @@ func (t *clientImpl) Close() { } } -func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) { - quicConn, err := t.getQuicConn(ctx, dialer, dialFn) +func (t *clientImpl) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) { + quicConn, err := t.getQuicConn(ctx) if err != nil { return nil, err } @@ -337,8 +333,8 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta return stream, nil } -func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) { - quicConn, err := t.getQuicConn(ctx, dialer, dialFn) +func (t *clientImpl) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) { + quicConn, err := t.getQuicConn(ctx) if err != nil { return nil, err } @@ -381,16 +377,16 @@ type Client struct { *clientImpl // use an independent pointer to let Finalizer can work no matter somewhere handle an influence in clientImpl inner } -func (t *Client) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) { - conn, err := t.clientImpl.DialContextWithDialer(ctx, metadata, dialer, dialFn) +func (t *Client) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) { + conn, err := t.clientImpl.DialContext(ctx, metadata) if err != nil { return nil, err } return N.NewRefConn(conn, t), err } -func (t *Client) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) { - pc, err := t.clientImpl.ListenPacketWithDialer(ctx, metadata, dialer, dialFn) +func (t *Client) ListenPacket(ctx context.Context, metadata *C.Metadata) (net.PacketConn, error) { + pc, err := t.clientImpl.ListenPacket(ctx, metadata) if err != nil { return nil, err } @@ -401,11 +397,11 @@ func (t *Client) forceClose() { t.clientImpl.forceClose(nil, common.ClientClosed) } -func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client { +func NewClient(clientOption *ClientOption, udp bool, dialFn common.DialFunc) *Client { ci := &clientImpl{ ClientOption: clientOption, + dialFn: dialFn, udp: udp, - dialerRef: dialerRef, } c := &Client{ci} runtime.SetFinalizer(c, closeClient) diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/v2ray-plugin/websocket.go b/clash-meta-android/core/src/foss/golang/clash/transport/v2ray-plugin/websocket.go index b2e37926e9..67b7c3ea20 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/v2ray-plugin/websocket.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/v2ray-plugin/websocket.go @@ -2,13 +2,14 @@ package obfs import ( "context" - "crypto/tls" "net" - "net/http" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" "github.com/metacubex/mihomo/transport/vmess" + + "github.com/metacubex/http" + "github.com/metacubex/tls" ) // Option is options of websocket obfs diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/client.go b/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/client.go index bcfce08ed8..03769f9dfe 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/client.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/client.go @@ -7,12 +7,23 @@ import ( "errors" "io" "net" + "runtime" "sync" "time" "github.com/metacubex/blake3" - utls "github.com/metacubex/utls" - "github.com/metacubex/utls/mlkem" + "github.com/metacubex/cpu" + "github.com/metacubex/mlkem" +) + +var ( + // Keep in sync with crypto/internal/fips140/aes/gcm.supportsAESGCM. + hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ && cpu.X86.HasSSE41 && cpu.X86.HasSSSE3 + hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL + hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCTR && cpu.S390X.HasGHASH + hasGCMAsmPPC64 = runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" + + HasAESGCMHardwareSupport = hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X || hasGCMAsmPPC64 ) type ClientInstance struct { @@ -66,7 +77,7 @@ func (i *ClientInstance) Handshake(conn net.Conn) (*CommonConn, error) { if i.NfsPKeys == nil { return nil, errors.New("uninitialized") } - c := NewCommonConn(conn, utls.HasAESGCMHardwareSupport()) + c := NewCommonConn(conn, HasAESGCMHardwareSupport) ivAndRealysLength := 16 + i.RelaysLength pfsKeyExchangeLength := 18 + 1184 + 32 + 16 diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/client_test.go b/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/client_test.go index 793d01919e..c61069e0e9 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/client_test.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/client_test.go @@ -4,17 +4,15 @@ import ( "fmt" "runtime" "testing" - - utls "github.com/metacubex/utls" ) func TestHasAESGCMHardwareSupport(t *testing.T) { - fmt.Println("HasAESGCMHardwareSupport:", utls.HasAESGCMHardwareSupport()) + fmt.Println("HasAESGCMHardwareSupport:", HasAESGCMHardwareSupport) if runtime.GOARCH == "arm64" && runtime.GOOS == "darwin" { // It should be supported starting from Apple Silicon M1 // https://github.com/golang/go/blob/go1.25.0/src/internal/cpu/cpu_arm64_darwin.go#L26-L30 - if !utls.HasAESGCMHardwareSupport() { + if !HasAESGCMHardwareSupport { t.Errorf("For ARM64 Darwin platforms (excluding iOS), AES GCM hardware acceleration should always be available.") } } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/key.go b/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/key.go index af9ac03379..98dd241c21 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/key.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/key.go @@ -7,7 +7,7 @@ import ( "fmt" "github.com/metacubex/blake3" - "github.com/metacubex/utls/mlkem" + "github.com/metacubex/mlkem" ) const MLKEM768SeedLength = mlkem.SeedSize diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/server.go b/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/server.go index 7118569888..7d0e86e9ef 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/vless/encryption/server.go @@ -13,7 +13,7 @@ import ( "time" "github.com/metacubex/blake3" - "github.com/metacubex/utls/mlkem" + "github.com/metacubex/mlkem" ) type ServerSession struct { diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/vless/vision/vision.go b/clash-meta-android/core/src/foss/golang/clash/transport/vless/vision/vision.go index e9786981eb..a77fba105d 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/vless/vision/vision.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/vless/vision/vision.go @@ -18,6 +18,7 @@ import ( "github.com/metacubex/mihomo/transport/vless/encryption" "github.com/gofrs/uuid/v5" + "github.com/metacubex/tls" ) var ErrNotHandshakeComplete = errors.New("tls connection not handshake complete") @@ -47,6 +48,13 @@ func NewConn(conn net.Conn, tlsConn net.Conn, userUUID uuid.UUID) (*Conn, error) t = reflect.TypeOf(underlying).Elem() p = unsafe.Pointer(underlying) break + case *tls.Conn: + //log.Debugln("type tls") + tlsConn = underlying + c.netConn = underlying.NetConn() + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + break case *tlsC.Conn: //log.Debugln("type *tlsC.Conn") tlsConn = underlying @@ -114,6 +122,14 @@ func checkTLSVersion(tlsConn net.Conn) error { if state.Version != gotls.VersionTLS13 { return ErrNotTLS13 } + case *tls.Conn: + state := underlying.ConnectionState() + if !state.HandshakeComplete { + return ErrNotHandshakeComplete + } + if state.Version != tls.VersionTLS13 { + return ErrNotTLS13 + } case *tlsC.Conn: state := underlying.ConnectionState() if !state.HandshakeComplete { diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/vmess/h2.go b/clash-meta-android/core/src/foss/golang/clash/transport/vmess/h2.go index 5ad24f3d27..a7244b0991 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/vmess/h2.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/vmess/h2.go @@ -4,18 +4,17 @@ import ( "context" "io" "net" - "net/http" "net/url" N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/http" "github.com/metacubex/randv2" - "golang.org/x/net/http2" ) type h2Conn struct { net.Conn - *http2.ClientConn + *http.Http2ClientConn pwriter *io.PipeWriter res *http.Response cfg *H2Config @@ -50,7 +49,7 @@ func (hc *h2Conn) establishConn() error { } // it will be close at : `func (hc *h2Conn) Close() error` - res, err := hc.ClientConn.RoundTrip(&req) + res, err := hc.Http2ClientConn.RoundTrip(&req) if err != nil { return err } @@ -96,7 +95,7 @@ func (hc *h2Conn) Close() error { if hc.res != nil { ctx = hc.res.Request.Context() } - if err := hc.ClientConn.Shutdown(ctx); err != nil { + if err := hc.Http2ClientConn.Shutdown(ctx); err != nil { return err } return hc.Conn.Close() @@ -108,7 +107,7 @@ func StreamH2Conn(ctx context.Context, conn net.Conn, cfg *H2Config) (_ net.Conn defer done(&err) } - transport := &http2.Transport{} + transport := &http.Http2Transport{} cconn, err := transport.NewClientConn(conn) if err != nil { @@ -116,8 +115,8 @@ func StreamH2Conn(ctx context.Context, conn net.Conn, cfg *H2Config) (_ net.Conn } return &h2Conn{ - Conn: conn, - ClientConn: cconn, - cfg: cfg, + Conn: conn, + Http2ClientConn: cconn, + cfg: cfg, }, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/vmess/http.go b/clash-meta-android/core/src/foss/golang/clash/transport/vmess/http.go index 94f1fbd351..77ac2ebebb 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/vmess/http.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/vmess/http.go @@ -5,11 +5,11 @@ import ( "bytes" "fmt" "net" - "net/http" "net/textproto" "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/http" "github.com/metacubex/randv2" ) diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/vmess/tls.go b/clash-meta-android/core/src/foss/golang/clash/transport/vmess/tls.go index 7239ebd238..4c4c50ec08 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/vmess/tls.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/vmess/tls.go @@ -2,13 +2,14 @@ package vmess import ( "context" - "crypto/tls" "errors" "net" "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/ech" tlsC "github.com/metacubex/mihomo/component/tls" + + "github.com/metacubex/tls" ) type TLSConfig struct { @@ -43,13 +44,12 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn } if clientFingerprint, ok := tlsC.GetFingerprint(cfg.ClientFingerprint); ok { - tlsConfig := tlsC.UConfig(tlsConfig) - err = cfg.ECH.ClientHandle(ctx, tlsConfig) - if err != nil { - return nil, err - } - if cfg.Reality == nil { + tlsConfig := tlsC.UConfig(tlsConfig) + err = cfg.ECH.ClientHandleUTLS(ctx, tlsConfig) + if err != nil { + return nil, err + } tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint) err = tlsConn.HandshakeContext(ctx) if err != nil { @@ -57,24 +57,16 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn } return tlsConn, nil } else { - return tlsC.GetRealityConn(ctx, conn, clientFingerprint, tlsConfig, cfg.Reality) + return tlsC.GetRealityConn(ctx, conn, clientFingerprint, tlsConfig.ServerName, cfg.Reality) } } if cfg.Reality != nil { return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint") } - if cfg.ECH != nil { - tlsConfig := tlsC.UConfig(tlsConfig) - err = cfg.ECH.ClientHandle(ctx, tlsConfig) - if err != nil { - return nil, err - } - - tlsConn := tlsC.Client(conn, tlsConfig) - - err = tlsConn.HandshakeContext(ctx) - return tlsConn, err + err = cfg.ECH.ClientHandle(ctx, tlsConfig) + if err != nil { + return nil, err } tlsConn := tls.Client(conn, tlsConfig) diff --git a/clash-meta-android/core/src/foss/golang/clash/transport/vmess/websocket.go b/clash-meta-android/core/src/foss/golang/clash/transport/vmess/websocket.go index 8fe436328d..0ee1b3ab2a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/transport/vmess/websocket.go +++ b/clash-meta-android/core/src/foss/golang/clash/transport/vmess/websocket.go @@ -5,15 +5,12 @@ import ( "bytes" "context" "crypto/rand" - "crypto/sha1" - "crypto/tls" "encoding/base64" "encoding/binary" "errors" "fmt" "io" "net" - "net/http" "net/url" "strconv" "strings" @@ -27,7 +24,9 @@ import ( "github.com/gobwas/ws" "github.com/gobwas/ws/wsutil" + "github.com/metacubex/http" "github.com/metacubex/randv2" + "github.com/metacubex/tls" ) type websocketConn struct { @@ -358,11 +357,11 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if clientFingerprint, ok := tlsC.GetFingerprint(c.ClientFingerprint); ok { tlsConfig := tlsC.UConfig(config) - err = c.ECHConfig.ClientHandle(ctx, tlsConfig) + err = c.ECHConfig.ClientHandleUTLS(ctx, tlsConfig) if err != nil { return nil, err } - tlsConn := tlsC.UClient(conn, tlsC.UConfig(config), clientFingerprint) + tlsConn := tlsC.UClient(conn, tlsConfig, clientFingerprint) if err = tlsC.BuildWebsocketHandshakeState(tlsConn); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } @@ -371,17 +370,11 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, return nil, err } conn = tlsConn - } else if c.ECHConfig != nil { - tlsConfig := tlsC.UConfig(config) - err = c.ECHConfig.ClientHandle(ctx, tlsConfig) + } else { + err = c.ECHConfig.ClientHandle(ctx, config) if err != nil { return nil, err } - tlsConn := tlsC.Client(conn, tlsConfig) - - err = tlsConn.HandshakeContext(ctx) - conn = tlsConn - } else { tlsConn := tls.Client(conn, config) err = tlsConn.HandshakeContext(ctx) if err != nil { @@ -478,7 +471,7 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if lenSecAccept := len(secAccept); lenSecAccept != acceptSize { return nil, fmt.Errorf("unexpected Sec-Websocket-Accept length: %d", lenSecAccept) } - if getSecAccept(secKey) != secAccept { + if N.GetWebSocketSecAccept(secKey) != secAccept { return nil, errors.New("unexpected Sec-Websocket-Accept") } } @@ -489,16 +482,6 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, return N.NewDeadlineConn(conn), nil } -func getSecAccept(secKey string) string { - const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - const nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize) - p := make([]byte, nonceSize+len(magic)) - copy(p[:nonceSize], secKey) - copy(p[nonceSize:], magic) - sum := sha1.Sum(p) - return base64.StdEncoding.EncodeToString(sum[:]) -} - func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig) (net.Conn, error) { if u, err := url.Parse(c.Path); err == nil { if q := u.Query(); q.Get("ed") != "" { @@ -568,7 +551,7 @@ func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Co w.Header().Set("Connection", "upgrade") w.Header().Set("Upgrade", "websocket") if !isRaw { - w.Header().Set("Sec-Websocket-Accept", getSecAccept(r.Header.Get("Sec-WebSocket-Key"))) + w.Header().Set("Sec-Websocket-Accept", N.GetWebSocketSecAccept(r.Header.Get("Sec-WebSocket-Key"))) } w.WriteHeader(http.StatusSwitchingProtocols) if flusher, isFlusher := w.(interface{ FlushError() error }); isFlusher && writeHeaderShouldFlush { diff --git a/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/manager.go b/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/manager.go index 9db4601e14..c69746dbcb 100644 --- a/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/manager.go +++ b/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/manager.go @@ -72,6 +72,10 @@ func (m *Manager) Now() (up int64, down int64) { return m.uploadBlip.Load(), m.downloadBlip.Load() } +func (m *Manager) Total() (up, down int64) { + return m.uploadTotal.Load(), m.downloadTotal.Load() +} + func (m *Manager) Memory() uint64 { m.updateMemory() return m.memory diff --git a/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/patch_android.go b/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/patch_android.go deleted file mode 100644 index f1eee346eb..0000000000 --- a/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/patch_android.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build android && cmfa - -package statistic - -func (m *Manager) Total() (up, down int64) { - return m.uploadTotal.Load(), m.downloadTotal.Load() -} diff --git a/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/tracker.go b/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/tracker.go index ffa2e71ede..2fbb1cf9e3 100644 --- a/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/tracker.go +++ b/clash-meta-android/core/src/foss/golang/clash/tunnel/statistic/tracker.go @@ -28,6 +28,7 @@ type TrackerInfo struct { DownloadTotal atomic.Int64 `json:"download"` Start time.Time `json:"start"` Chain C.Chain `json:"chains"` + ProviderChain C.Chain `json:"providerChains"` Rule string `json:"rule"` RulePayload string `json:"rulePayload"` } @@ -126,6 +127,7 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R Start: time.Now(), Metadata: metadata, Chain: conn.Chains(), + ProviderChain: conn.ProviderChains(), Rule: "", UploadTotal: atomic.NewInt64(uploadTotal), DownloadTotal: atomic.NewInt64(downloadTotal), @@ -217,6 +219,7 @@ func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, ru Start: time.Now(), Metadata: metadata, Chain: conn.Chains(), + ProviderChain: conn.ProviderChains(), Rule: "", UploadTotal: atomic.NewInt64(uploadTotal), DownloadTotal: atomic.NewInt64(downloadTotal), diff --git a/clash-meta-android/core/src/foss/golang/go.mod b/clash-meta-android/core/src/foss/golang/go.mod index 27d4f6bc45..4ea70e3cec 100644 --- a/clash-meta-android/core/src/foss/golang/go.mod +++ b/clash-meta-android/core/src/foss/golang/go.mod @@ -21,10 +21,7 @@ require ( github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect - github.com/go-chi/chi/v5 v5.2.3 // indirect - github.com/go-chi/render v1.0.3 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/ws v1.4.0 // indirect @@ -32,7 +29,7 @@ require ( github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect + github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -47,39 +44,44 @@ require ( github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b // indirect github.com/metacubex/blake3 v0.1.0 // indirect github.com/metacubex/chacha v0.1.5 // indirect + github.com/metacubex/chi v0.1.0 // indirect + github.com/metacubex/cpu v0.1.0 // indirect github.com/metacubex/fswatch v0.1.1 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20250919004547-6122b699a301 // indirect + github.com/metacubex/hkdf v0.1.0 // indirect + github.com/metacubex/hpke v0.1.0 // indirect + github.com/metacubex/http v0.1.0 // indirect github.com/metacubex/kcp-go v0.0.0-20251111012849-7455698490e9 // indirect github.com/metacubex/mihomo v1.7.0 // indirect + github.com/metacubex/mlkem v0.1.0 // indirect github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect - github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128 // indirect + github.com/metacubex/qpack v0.6.0 // indirect + github.com/metacubex/quic-go v0.57.1-0.20251217071004-e89f497a2e72 // indirect github.com/metacubex/randv2 v0.2.0 // indirect github.com/metacubex/restls-client-go v0.1.7 // indirect github.com/metacubex/sing v0.5.6 // indirect github.com/metacubex/sing-mux v0.3.4 // indirect - github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb // indirect + github.com/metacubex/sing-quic v0.0.0-20251217080445-b15217cb57f3 // indirect github.com/metacubex/sing-shadowsocks v0.2.12 // indirect github.com/metacubex/sing-shadowsocks2 v0.2.7 // indirect github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 // indirect - github.com/metacubex/sing-tun v0.4.10 // indirect + github.com/metacubex/sing-tun v0.4.11 // indirect github.com/metacubex/sing-vmess v0.2.4 // indirect github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f // indirect github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1 // indirect github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 // indirect + github.com/metacubex/tls v0.1.0 // indirect github.com/metacubex/utls v1.8.3 // indirect github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f // indirect github.com/metacubex/yamux v0.0.0-20250918083631-dd5f17c0be49 // indirect github.com/miekg/dns v1.1.63 // indirect github.com/mroth/weightedrand/v2 v2.1.0 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect - github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/openacid/low v0.1.21 // indirect github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect - github.com/quic-go/qpack v0.4.0 // indirect - github.com/saba-futai/sudoku v0.0.1-g // indirect - github.com/sagernet/cors v1.2.1 // indirect + github.com/saba-futai/sudoku v0.0.2-d // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/samber/lo v1.52.0 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect @@ -101,7 +103,7 @@ require ( golang.org/x/sync v0.11.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect - golang.org/x/time v0.7.0 // indirect + golang.org/x/time v0.10.0 // indirect golang.org/x/tools v0.24.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/clash-meta-android/core/src/foss/golang/go.sum b/clash-meta-android/core/src/foss/golang/go.sum index f60cf07b72..5e8e0108e8 100644 --- a/clash-meta-android/core/src/foss/golang/go.sum +++ b/clash-meta-android/core/src/foss/golang/go.sum @@ -14,9 +14,6 @@ github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xW github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc= github.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -39,15 +36,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= -github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= -github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= -github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= -github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= @@ -57,17 +47,15 @@ github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakr github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0= github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4= github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -98,18 +86,32 @@ github.com/metacubex/blake3 v0.1.0 h1:KGnjh/56REO7U+cgZA8dnBhxdP7jByrG7hTP+bu6cq github.com/metacubex/blake3 v0.1.0/go.mod h1:CCkLdzFrqf7xmxCdhQFvJsRRV2mwOLDoSPg6vUTB9Uk= github.com/metacubex/chacha v0.1.5 h1:fKWMb/5c7ZrY8Uoqi79PPFxl+qwR7X/q0OrsAubyX2M= github.com/metacubex/chacha v0.1.5/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8= +github.com/metacubex/chi v0.1.0 h1:rjNDyDj50nRpicG43CNkIw4ssiCbmDL8d7wJXKlUCsg= +github.com/metacubex/chi v0.1.0/go.mod h1:zM5u5oMQt8b2DjvDHvzadKrP6B2ztmasL1YHRMbVV+g= +github.com/metacubex/cpu v0.1.0 h1:8PeTdV9j6UKbN1K5Jvtbi/Jock7dknvzyYuLb8Conmk= +github.com/metacubex/cpu v0.1.0/go.mod h1:09VEt4dSRLR+bOA8l4w4NDuzGZ8n5dkMv7e8axgEeTU= github.com/metacubex/fswatch v0.1.1 h1:jqU7C/v+g0qc2RUFgmAOPoVvfl2BXXUXEumn6oQuxhU= github.com/metacubex/fswatch v0.1.1/go.mod h1:czrTT7Zlbz7vWft8RQu9Qqh+JoX+Nnb+UabuyN1YsgI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20250919004547-6122b699a301 h1:N5GExQJqYAH3gOCshpp2u/J3CtNYzMctmlb0xK9wtbQ= github.com/metacubex/gvisor v0.0.0-20250919004547-6122b699a301/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU= +github.com/metacubex/hkdf v0.1.0 h1:fPA6VzXK8cU1foc/TOmGCDmSa7pZbxlnqhl3RNsthaA= +github.com/metacubex/hkdf v0.1.0/go.mod h1:3seEfds3smgTAXqUGn+tgEJH3uXdsUjOiduG/2EtvZ4= +github.com/metacubex/hpke v0.1.0 h1:gu2jUNhraehWi0P/z5HX2md3d7L1FhPQE6/Q0E9r9xQ= +github.com/metacubex/hpke v0.1.0/go.mod h1:vfDm6gfgrwlXUxKDkWbcE44hXtmc1uxLDm2BcR11b3U= +github.com/metacubex/http v0.1.0 h1:Jcy0I9zKjYijSUaksZU34XEe2xNdoFkgUTB7z7K5q0o= +github.com/metacubex/http v0.1.0/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg= github.com/metacubex/kcp-go v0.0.0-20251111012849-7455698490e9 h1:7m3tRPrLpKOLOvZ/Lp4XCxz0t7rg9t9K35x6TahjR8o= github.com/metacubex/kcp-go v0.0.0-20251111012849-7455698490e9/go.mod h1:HIJZW4QMhbBqXuqC1ly6Hn0TEYT2SzRw58ns1yGhXTs= +github.com/metacubex/mlkem v0.1.0 h1:wFClitonSFcmipzzQvax75beLQU+D7JuC+VK1RzSL8I= +github.com/metacubex/mlkem v0.1.0/go.mod h1:amhaXZVeYNShuy9BILcR7P0gbeo/QLZsnqCdL8U2PDQ= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA= -github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128 h1:I1uvJl206/HbkzEAZpLgGkZgUveOZb+P+6oTUj7dN+o= -github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c= +github.com/metacubex/qpack v0.6.0 h1:YqClGIMOpiRYLjV1qOs483Od08MdPgRnHjt90FuaAKw= +github.com/metacubex/qpack v0.6.0/go.mod h1:lKGSi7Xk94IMvHGOmxS9eIei3bvIqpOAImEBsaOwTkA= +github.com/metacubex/quic-go v0.57.1-0.20251217071004-e89f497a2e72 h1:kNlYHZ75itJwkerDiySpixX+dKsv/K0TYQsKvuxogNM= +github.com/metacubex/quic-go v0.57.1-0.20251217071004-e89f497a2e72/go.mod h1:N071X2oW2+kIhLlHW3mfcD2QP+zWu2bEs1EEAm66bvI= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k= @@ -119,16 +121,16 @@ github.com/metacubex/sing v0.5.6 h1:mEPDCadsCj3DB8gn+t/EtposlYuALEkExa/LUguw6/c= github.com/metacubex/sing v0.5.6/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w= github.com/metacubex/sing-mux v0.3.4 h1:tf4r27CIkzaxq9kBlAXQkgMXq2HPp5Mta60Kb4RCZF0= github.com/metacubex/sing-mux v0.3.4/go.mod h1:SEJfAuykNj/ozbPqngEYqyggwSr81+L7Nu09NRD5mh4= -github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb h1:gxrJmnxuEAel+kh3V7ntqkHjURif0xKDu76nzr/BF5Y= -github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb/go.mod h1:JK4+PYUKps6pnlicKjsSUAjAcvIUjhorIjdNZGg930M= +github.com/metacubex/sing-quic v0.0.0-20251217080445-b15217cb57f3 h1:3LlkguIRAzyBWLxP5xrETi1AMIt3McZcDlXNgiyXMsE= +github.com/metacubex/sing-quic v0.0.0-20251217080445-b15217cb57f3/go.mod h1:fAyoc/8IFK1yJp8meJvPNyGk7ZnKG1vmNaTwYx6NHA4= github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE= github.com/metacubex/sing-shadowsocks v0.2.12/go.mod h1:2e5EIaw0rxKrm1YTRmiMnDulwbGxH9hAFlrwQLQMQkU= github.com/metacubex/sing-shadowsocks2 v0.2.7 h1:hSuuc0YpsfiqYqt1o+fP4m34BQz4e6wVj3PPBVhor3A= github.com/metacubex/sing-shadowsocks2 v0.2.7/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE= github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI= github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E= -github.com/metacubex/sing-tun v0.4.10 h1:DllQTERAcqQyiEl4L/R7Ia0jCiSzZzikw2kL8N85p0E= -github.com/metacubex/sing-tun v0.4.10/go.mod h1:L/TjQY5JEGy8nvsuYmy/XgMFMCPiF0+AWSFCYfS6r9w= +github.com/metacubex/sing-tun v0.4.11 h1:NG5zpvYPbBXf+9GSUmDaGCDwl3hZXV677tbRAw0QtCM= +github.com/metacubex/sing-tun v0.4.11/go.mod h1:L/TjQY5JEGy8nvsuYmy/XgMFMCPiF0+AWSFCYfS6r9w= github.com/metacubex/sing-vmess v0.2.4 h1:Tx6AGgCiEf400E/xyDuYyafsel6sGbR8oF7RkAaus6I= github.com/metacubex/sing-vmess v0.2.4/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM= github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU= @@ -137,6 +139,8 @@ github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1 h1:a6DF0ze9miXes+rd github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE= github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 h1:H6TnfM12tOoTizYE/qBHH3nEuibIelmHI+BVSxVJr8o= github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= +github.com/metacubex/tls v0.1.0 h1:1kjR/1q2uU1cZIwiHYEnWzS4L+0Cu1/X3yfIQ76BzNY= +github.com/metacubex/tls v0.1.0/go.mod h1:0XeVdL0cBw+8i5Hqy3lVeP9IyD/LFTq02ExvHM6rzEM= github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4= github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk= @@ -149,9 +153,6 @@ github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0= github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= @@ -164,12 +165,8 @@ github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= -github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/saba-futai/sudoku v0.0.1-g h1:4q6OuAA6COaRW+CgoQtdim5AUPzzm0uOkvbYpJnOaBE= -github.com/saba-futai/sudoku v0.0.1-g/go.mod h1:2ZRzRwz93cS2K/o2yOG4CPJEltcvk5y6vbvUmjftGU0= -github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= -github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= +github.com/saba-futai/sudoku v0.0.2-d h1:HW/gIyNUFcDchpMN+ZhluM86U/HGkWkkRV+9Km6WZM8= +github.com/saba-futai/sudoku v0.0.2-d/go.mod h1:Rvggsoprp7HQM7bMIZUd1M27bPj8THRsZdY1dGbIAvo= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= @@ -236,7 +233,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -250,8 +246,8 @@ golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= diff --git a/clash-meta-android/core/src/main/golang/go.mod b/clash-meta-android/core/src/main/golang/go.mod index 17f3c9de99..1d84c5a1e2 100644 --- a/clash-meta-android/core/src/main/golang/go.mod +++ b/clash-meta-android/core/src/main/golang/go.mod @@ -27,19 +27,15 @@ require ( github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect - github.com/go-chi/chi/v5 v5.2.3 // indirect - github.com/go-chi/render v1.0.3 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/gobwas/ws v1.4.0 // indirect github.com/gofrs/uuid/v5 v5.4.0 // indirect - github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect + github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -54,38 +50,43 @@ require ( github.com/metacubex/bbolt v0.0.0-20250725135710-010dbbbb7a5b // indirect github.com/metacubex/blake3 v0.1.0 // indirect github.com/metacubex/chacha v0.1.5 // indirect + github.com/metacubex/chi v0.1.0 // indirect + github.com/metacubex/cpu v0.1.0 // indirect github.com/metacubex/fswatch v0.1.1 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20250919004547-6122b699a301 // indirect + github.com/metacubex/hkdf v0.1.0 // indirect + github.com/metacubex/hpke v0.1.0 // indirect + github.com/metacubex/http v0.1.0 // indirect github.com/metacubex/kcp-go v0.0.0-20251111012849-7455698490e9 // indirect + github.com/metacubex/mlkem v0.1.0 // indirect github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 // indirect - github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128 // indirect + github.com/metacubex/qpack v0.6.0 // indirect + github.com/metacubex/quic-go v0.57.1-0.20251217071004-e89f497a2e72 // indirect github.com/metacubex/randv2 v0.2.0 // indirect github.com/metacubex/restls-client-go v0.1.7 // indirect github.com/metacubex/sing v0.5.6 // indirect github.com/metacubex/sing-mux v0.3.4 // indirect - github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb // indirect + github.com/metacubex/sing-quic v0.0.0-20251217080445-b15217cb57f3 // indirect github.com/metacubex/sing-shadowsocks v0.2.12 // indirect github.com/metacubex/sing-shadowsocks2 v0.2.7 // indirect github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 // indirect - github.com/metacubex/sing-tun v0.4.10 // indirect + github.com/metacubex/sing-tun v0.4.11 // indirect github.com/metacubex/sing-vmess v0.2.4 // indirect github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f // indirect github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1 // indirect github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 // indirect + github.com/metacubex/tls v0.1.0 // indirect github.com/metacubex/utls v1.8.3 // indirect github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f // indirect github.com/metacubex/yamux v0.0.0-20250918083631-dd5f17c0be49 // indirect github.com/miekg/dns v1.1.63 // indirect github.com/mroth/weightedrand/v2 v2.1.0 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect - github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/openacid/low v0.1.21 // indirect github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect - github.com/quic-go/qpack v0.4.0 // indirect - github.com/saba-futai/sudoku v0.0.1-g // indirect - github.com/sagernet/cors v1.2.1 // indirect + github.com/saba-futai/sudoku v0.0.2-d // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/samber/lo v1.52.0 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect @@ -106,7 +107,7 @@ require ( golang.org/x/net v0.35.0 // indirect golang.org/x/sys v0.30.0 // indirect golang.org/x/text v0.22.0 // indirect - golang.org/x/time v0.7.0 // indirect + golang.org/x/time v0.10.0 // indirect golang.org/x/tools v0.24.0 // indirect google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/clash-meta-android/core/src/main/golang/go.sum b/clash-meta-android/core/src/main/golang/go.sum index be217130ef..5e8e0108e8 100644 --- a/clash-meta-android/core/src/main/golang/go.sum +++ b/clash-meta-android/core/src/main/golang/go.sum @@ -14,9 +14,6 @@ github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xW github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/coreos/go-iptables v0.8.0 h1:MPc2P89IhuVpLI7ETL/2tx3XZ61VeICZjYqDEgNsPRc= github.com/coreos/go-iptables v0.8.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -39,15 +36,8 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= -github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= -github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= -github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= -github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= @@ -57,18 +47,15 @@ github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakr github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0= github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905 h1:q3OEI9RaN/wwcx+qgGo6ZaoJkCiDYe/gjDLfq7lQQF4= github.com/insomniacslk/dhcp v0.0.0-20250109001534-8abf58130905/go.mod h1:VvGYjkZoJyKqlmT1yzakUs4mfKMNB0XdODP0+rdml6k= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -99,18 +86,32 @@ github.com/metacubex/blake3 v0.1.0 h1:KGnjh/56REO7U+cgZA8dnBhxdP7jByrG7hTP+bu6cq github.com/metacubex/blake3 v0.1.0/go.mod h1:CCkLdzFrqf7xmxCdhQFvJsRRV2mwOLDoSPg6vUTB9Uk= github.com/metacubex/chacha v0.1.5 h1:fKWMb/5c7ZrY8Uoqi79PPFxl+qwR7X/q0OrsAubyX2M= github.com/metacubex/chacha v0.1.5/go.mod h1:Djn9bPZxLTXbJFSeyo0/qzEzQI+gUSSzttuzZM75GH8= +github.com/metacubex/chi v0.1.0 h1:rjNDyDj50nRpicG43CNkIw4ssiCbmDL8d7wJXKlUCsg= +github.com/metacubex/chi v0.1.0/go.mod h1:zM5u5oMQt8b2DjvDHvzadKrP6B2ztmasL1YHRMbVV+g= +github.com/metacubex/cpu v0.1.0 h1:8PeTdV9j6UKbN1K5Jvtbi/Jock7dknvzyYuLb8Conmk= +github.com/metacubex/cpu v0.1.0/go.mod h1:09VEt4dSRLR+bOA8l4w4NDuzGZ8n5dkMv7e8axgEeTU= github.com/metacubex/fswatch v0.1.1 h1:jqU7C/v+g0qc2RUFgmAOPoVvfl2BXXUXEumn6oQuxhU= github.com/metacubex/fswatch v0.1.1/go.mod h1:czrTT7Zlbz7vWft8RQu9Qqh+JoX+Nnb+UabuyN1YsgI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20250919004547-6122b699a301 h1:N5GExQJqYAH3gOCshpp2u/J3CtNYzMctmlb0xK9wtbQ= github.com/metacubex/gvisor v0.0.0-20250919004547-6122b699a301/go.mod h1:8LpS0IJW1VmWzUm3ylb0e2SK5QDm5lO/2qwWLZgRpBU= +github.com/metacubex/hkdf v0.1.0 h1:fPA6VzXK8cU1foc/TOmGCDmSa7pZbxlnqhl3RNsthaA= +github.com/metacubex/hkdf v0.1.0/go.mod h1:3seEfds3smgTAXqUGn+tgEJH3uXdsUjOiduG/2EtvZ4= +github.com/metacubex/hpke v0.1.0 h1:gu2jUNhraehWi0P/z5HX2md3d7L1FhPQE6/Q0E9r9xQ= +github.com/metacubex/hpke v0.1.0/go.mod h1:vfDm6gfgrwlXUxKDkWbcE44hXtmc1uxLDm2BcR11b3U= +github.com/metacubex/http v0.1.0 h1:Jcy0I9zKjYijSUaksZU34XEe2xNdoFkgUTB7z7K5q0o= +github.com/metacubex/http v0.1.0/go.mod h1:Nxx0zZAo2AhRfanyL+fmmK6ACMtVsfpwIl1aFAik2Eg= github.com/metacubex/kcp-go v0.0.0-20251111012849-7455698490e9 h1:7m3tRPrLpKOLOvZ/Lp4XCxz0t7rg9t9K35x6TahjR8o= github.com/metacubex/kcp-go v0.0.0-20251111012849-7455698490e9/go.mod h1:HIJZW4QMhbBqXuqC1ly6Hn0TEYT2SzRw58ns1yGhXTs= +github.com/metacubex/mlkem v0.1.0 h1:wFClitonSFcmipzzQvax75beLQU+D7JuC+VK1RzSL8I= +github.com/metacubex/mlkem v0.1.0/go.mod h1:amhaXZVeYNShuy9BILcR7P0gbeo/QLZsnqCdL8U2PDQ= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793 h1:1Qpuy+sU3DmyX9HwI+CrBT/oLNJngvBorR2RbajJcqo= github.com/metacubex/nftables v0.0.0-20250503052935-30a69ab87793/go.mod h1:RjRNb4G52yAgfR+Oe/kp9G4PJJ97Fnj89eY1BFO3YyA= -github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128 h1:I1uvJl206/HbkzEAZpLgGkZgUveOZb+P+6oTUj7dN+o= -github.com/metacubex/quic-go v0.55.1-0.20251024060151-bd465f127128/go.mod h1:1lktQFtCD17FZliVypbrDHwbsFSsmz2xz2TRXydvB5c= +github.com/metacubex/qpack v0.6.0 h1:YqClGIMOpiRYLjV1qOs483Od08MdPgRnHjt90FuaAKw= +github.com/metacubex/qpack v0.6.0/go.mod h1:lKGSi7Xk94IMvHGOmxS9eIei3bvIqpOAImEBsaOwTkA= +github.com/metacubex/quic-go v0.57.1-0.20251217071004-e89f497a2e72 h1:kNlYHZ75itJwkerDiySpixX+dKsv/K0TYQsKvuxogNM= +github.com/metacubex/quic-go v0.57.1-0.20251217071004-e89f497a2e72/go.mod h1:N071X2oW2+kIhLlHW3mfcD2QP+zWu2bEs1EEAm66bvI= github.com/metacubex/randv2 v0.2.0 h1:uP38uBvV2SxYfLj53kuvAjbND4RUDfFJjwr4UigMiLs= github.com/metacubex/randv2 v0.2.0/go.mod h1:kFi2SzrQ5WuneuoLLCMkABtiBu6VRrMrWFqSPyj2cxY= github.com/metacubex/restls-client-go v0.1.7 h1:eCwiXCTQb5WJu9IlgYvDBA1OgrINv58dEe7hcN5H15k= @@ -120,16 +121,16 @@ github.com/metacubex/sing v0.5.6 h1:mEPDCadsCj3DB8gn+t/EtposlYuALEkExa/LUguw6/c= github.com/metacubex/sing v0.5.6/go.mod h1:ypf0mjwlZm0sKdQSY+yQvmsbWa0hNPtkeqyRMGgoN+w= github.com/metacubex/sing-mux v0.3.4 h1:tf4r27CIkzaxq9kBlAXQkgMXq2HPp5Mta60Kb4RCZF0= github.com/metacubex/sing-mux v0.3.4/go.mod h1:SEJfAuykNj/ozbPqngEYqyggwSr81+L7Nu09NRD5mh4= -github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb h1:gxrJmnxuEAel+kh3V7ntqkHjURif0xKDu76nzr/BF5Y= -github.com/metacubex/sing-quic v0.0.0-20251004051927-c45ee18473bb/go.mod h1:JK4+PYUKps6pnlicKjsSUAjAcvIUjhorIjdNZGg930M= +github.com/metacubex/sing-quic v0.0.0-20251217080445-b15217cb57f3 h1:3LlkguIRAzyBWLxP5xrETi1AMIt3McZcDlXNgiyXMsE= +github.com/metacubex/sing-quic v0.0.0-20251217080445-b15217cb57f3/go.mod h1:fAyoc/8IFK1yJp8meJvPNyGk7ZnKG1vmNaTwYx6NHA4= github.com/metacubex/sing-shadowsocks v0.2.12 h1:Wqzo8bYXrK5aWqxu/TjlTnYZzAKtKsaFQBdr6IHFaBE= github.com/metacubex/sing-shadowsocks v0.2.12/go.mod h1:2e5EIaw0rxKrm1YTRmiMnDulwbGxH9hAFlrwQLQMQkU= github.com/metacubex/sing-shadowsocks2 v0.2.7 h1:hSuuc0YpsfiqYqt1o+fP4m34BQz4e6wVj3PPBVhor3A= github.com/metacubex/sing-shadowsocks2 v0.2.7/go.mod h1:vOEbfKC60txi0ca+yUlqEwOGc3Obl6cnSgx9Gf45KjE= github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2 h1:gXU+MYPm7Wme3/OAY2FFzVq9d9GxPHOqu5AQfg/ddhI= github.com/metacubex/sing-shadowtls v0.0.0-20250503063515-5d9f966d17a2/go.mod h1:mbfboaXauKJNIHJYxQRa+NJs4JU9NZfkA+I33dS2+9E= -github.com/metacubex/sing-tun v0.4.10 h1:DllQTERAcqQyiEl4L/R7Ia0jCiSzZzikw2kL8N85p0E= -github.com/metacubex/sing-tun v0.4.10/go.mod h1:L/TjQY5JEGy8nvsuYmy/XgMFMCPiF0+AWSFCYfS6r9w= +github.com/metacubex/sing-tun v0.4.11 h1:NG5zpvYPbBXf+9GSUmDaGCDwl3hZXV677tbRAw0QtCM= +github.com/metacubex/sing-tun v0.4.11/go.mod h1:L/TjQY5JEGy8nvsuYmy/XgMFMCPiF0+AWSFCYfS6r9w= github.com/metacubex/sing-vmess v0.2.4 h1:Tx6AGgCiEf400E/xyDuYyafsel6sGbR8oF7RkAaus6I= github.com/metacubex/sing-vmess v0.2.4/go.mod h1:21R5R1u90uUvBQF0owoooEu96/SAYYD56nDrwm6nFaM= github.com/metacubex/sing-wireguard v0.0.0-20250503063753-2dc62acc626f h1:Sr/DYKYofKHKc4GF3qkRGNuj6XA6c0eqPgEDN+VAsYU= @@ -138,6 +139,8 @@ github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1 h1:a6DF0ze9miXes+rd github.com/metacubex/smux v0.0.0-20251111013112-03f8d12dafc1/go.mod h1:4bPD8HWx9jPJ9aE4uadgyN7D1/Wz3KmPy+vale8sKLE= github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443 h1:H6TnfM12tOoTizYE/qBHH3nEuibIelmHI+BVSxVJr8o= github.com/metacubex/tfo-go v0.0.0-20251130171125-413e892ac443/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= +github.com/metacubex/tls v0.1.0 h1:1kjR/1q2uU1cZIwiHYEnWzS4L+0Cu1/X3yfIQ76BzNY= +github.com/metacubex/tls v0.1.0/go.mod h1:0XeVdL0cBw+8i5Hqy3lVeP9IyD/LFTq02ExvHM6rzEM= github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4= github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= github.com/metacubex/wireguard-go v0.0.0-20250820062549-a6cecdd7f57f h1:FGBPRb1zUabhPhDrlKEjQ9lgIwQ6cHL4x8M9lrERhbk= @@ -150,9 +153,6 @@ github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0= github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= @@ -165,12 +165,8 @@ github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= -github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/saba-futai/sudoku v0.0.1-g h1:4q6OuAA6COaRW+CgoQtdim5AUPzzm0uOkvbYpJnOaBE= -github.com/saba-futai/sudoku v0.0.1-g/go.mod h1:2ZRzRwz93cS2K/o2yOG4CPJEltcvk5y6vbvUmjftGU0= -github.com/sagernet/cors v1.2.1 h1:Cv5Z8y9YSD6Gm+qSpNrL3LO4lD3eQVvbFYJSG7JCMHQ= -github.com/sagernet/cors v1.2.1/go.mod h1:O64VyOjjhrkLmQIjF4KGRrJO/5dVXFdpEmCW/eISRAI= +github.com/saba-futai/sudoku v0.0.2-d h1:HW/gIyNUFcDchpMN+ZhluM86U/HGkWkkRV+9Km6WZM8= +github.com/saba-futai/sudoku v0.0.2-d/go.mod h1:Rvggsoprp7HQM7bMIZUd1M27bPj8THRsZdY1dGbIAvo= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis= github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw= @@ -237,7 +233,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -251,8 +246,8 @@ golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= +golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= diff --git a/clash-meta/transport/gun/gun.go b/clash-meta/transport/gun/gun.go index 35639c12be..3ac548ddfc 100644 --- a/clash-meta/transport/gun/gun.go +++ b/clash-meta/transport/gun/gun.go @@ -12,6 +12,7 @@ import ( "io" "net" "net/url" + "strings" "sync" "time" @@ -331,11 +332,19 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri return wrap } +func ServiceNameToPath(serviceName string) string { + if strings.HasPrefix(serviceName, "/") { // custom paths + return serviceName + } + return "/" + serviceName + "/Tun" +} + func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, error) { serviceName := "GunService" if cfg.ServiceName != "" { serviceName = cfg.ServiceName } + path := ServiceNameToPath(serviceName) reader, writer := io.Pipe() request := &http.Request{ @@ -344,9 +353,9 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er URL: &url.URL{ Scheme: "https", Host: cfg.Host, - Path: fmt.Sprintf("/%s/Tun", serviceName), + Path: path, // for unescape path - Opaque: fmt.Sprintf("//%s/%s/Tun", cfg.Host, serviceName), + Opaque: "//" + cfg.Host + path, }, Proto: "HTTP/2", ProtoMajor: 2, diff --git a/clash-meta/transport/gun/server.go b/clash-meta/transport/gun/server.go index 16605b4342..c240459fee 100644 --- a/clash-meta/transport/gun/server.go +++ b/clash-meta/transport/gun/server.go @@ -24,7 +24,7 @@ type ServerOption struct { } func NewServerHandler(options ServerOption) http.Handler { - path := "/" + options.ServiceName + "/Tun" + path := ServiceNameToPath(options.ServiceName) connHandler := options.ConnHandler httpHandler := options.HttpHandler if httpHandler == nil { diff --git a/clash-nyanpasu/backend/Cargo.lock b/clash-nyanpasu/backend/Cargo.lock index 4ab30a4d56..636dc4bc94 100644 --- a/clash-nyanpasu/backend/Cargo.lock +++ b/clash-nyanpasu/backend/Cargo.lock @@ -748,9 +748,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", "base64 0.22.1", @@ -7938,7 +7938,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] diff --git a/clash-nyanpasu/backend/tauri/src/utils/resolve.rs b/clash-nyanpasu/backend/tauri/src/utils/resolve.rs index 23ee02d55f..18056c9074 100644 --- a/clash-nyanpasu/backend/tauri/src/utils/resolve.rs +++ b/clash-nyanpasu/backend/tauri/src/utils/resolve.rs @@ -354,7 +354,7 @@ pub fn create_window(app_handle: &AppHandle) { { tracing::trace!("setup traffic lights pos"); let mtm = objc2_foundation::MainThreadMarker::new().unwrap(); - crate::window::macos::setup_traffic_lights_pos(win.clone(), (26.0, 26.0), mtm); + crate::window::macos::setup_traffic_lights_pos(win.clone(), (18.0, 22.0), mtm); } OPEN_WINDOWS_COUNTER.fetch_add(1, Ordering::Release); diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index 7556ae0bf6..bf6a5f1b6f 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -14,7 +14,7 @@ "@dnd-kit/sortable": "10.0.0", "@dnd-kit/utilities": "3.2.2", "@emotion/styled": "11.14.1", - "@hookform/resolvers": "^5.2.2", + "@hookform/resolvers": "5.2.2", "@inlang/paraglide-js": "2.7.0", "@juggle/resize-observer": "3.4.0", "@material/material-color-utilities": "0.3.0", @@ -27,7 +27,7 @@ "@radix-ui/react-dropdown-menu": "2.1.16", "@radix-ui/react-scroll-area": "1.2.10", "@radix-ui/react-select": "2.2.6", - "@radix-ui/react-separator": "^1.1.8", + "@radix-ui/react-separator": "1.1.8", "@radix-ui/react-slot": "1.2.4", "@radix-ui/react-switch": "1.2.6", "@radix-ui/react-use-controllable-state": "1.2.2", @@ -54,7 +54,7 @@ "react-dom": "19.2.0", "react-error-boundary": "6.0.0", "react-fast-marquee": "1.6.5", - "react-hook-form": "^7.69.0", + "react-hook-form": "7.69.0", "react-hook-form-mui": "8.2.0", "react-i18next": "15.7.4", "react-markdown": "10.1.0", @@ -87,7 +87,7 @@ "@types/react-dom": "19.2.3", "@types/validator": "13.15.10", "@vitejs/plugin-legacy": "7.2.1", - "@vitejs/plugin-react": "5.1.1", + "@vitejs/plugin-react": "5.1.2", "@vitejs/plugin-react-swc": "4.2.2", "change-case": "5.4.4", "clsx": "2.1.1", @@ -101,9 +101,9 @@ "unplugin-auto-import": "20.3.0", "unplugin-icons": "22.5.0", "validator": "13.15.26", - "vite": "7.2.4", + "vite": "7.3.0", "vite-plugin-html": "3.2.2", - "vite-plugin-sass-dts": "1.3.34", + "vite-plugin-sass-dts": "1.3.35", "vite-plugin-svgr": "4.5.0", "vite-tsconfig-paths": "5.1.4", "zod": "4.1.13" diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.tsx index 100678a092..46885c90bc 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/app/app-container.tsx @@ -78,7 +78,7 @@ export const AppContainer = ({ {/* TODO: add a framer motion animation to toggle the maximized state */} {OS === 'macos' && !isMaximized && ( ({ backgroundColor: alpha(theme.vars.palette.primary.main, 0.1), })} diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/ui/scroll-area.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/ui/scroll-area.tsx index f85da1c86f..5c6249bacf 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/ui/scroll-area.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/ui/scroll-area.tsx @@ -1,8 +1,72 @@ import * as React from 'react' -import { useRef, useState } from 'react' +import { createContext, useContext, useRef, useState } from 'react' import { cn } from '@nyanpasu/ui' import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area' +interface ScrollAreaContextValue { + isTop: boolean + isBottom: boolean + scrollDirection: 'up' | 'down' | 'left' | 'right' | 'none' + viewportRef: React.RefObject +} + +const ScrollAreaContext = createContext(null) + +export function useScrollArea() { + const context = useContext(ScrollAreaContext) + + if (!context) { + throw new Error('useScrollArea must be used within a ScrollArea component') + } + + return context +} + +function useScrollTracking(threshold = 50) { + const [isTop, setIsTop] = useState(true) + const [isBottom, setIsBottom] = useState(false) + const [scrollDirection, setScrollDirection] = useState< + 'up' | 'down' | 'left' | 'right' | 'none' + >('none') + + const lastScrollTop = useRef(0) + const lastScrollLeft = useRef(0) + + const handleScroll = (e: React.UIEvent) => { + const target = e.currentTarget as HTMLElement + const { scrollTop, scrollLeft, scrollHeight, clientHeight } = target + + setIsTop(scrollTop === 0) + + // check if is at bottom, allow a small threshold + const isAtBottom = scrollHeight - scrollTop - clientHeight < threshold + setIsBottom(isAtBottom) + + const deltaY = scrollTop - lastScrollTop.current + const deltaX = scrollLeft - lastScrollLeft.current + + // Determine primary scroll direction + if (Math.abs(deltaY) > Math.abs(deltaX)) { + if (deltaY > 0) { + setScrollDirection('down') + } else if (deltaY < 0) { + setScrollDirection('up') + } + } else if (Math.abs(deltaX) > Math.abs(deltaY)) { + if (deltaX > 0) { + setScrollDirection('right') + } else if (deltaX < 0) { + setScrollDirection('left') + } + } + + lastScrollTop.current = scrollTop + lastScrollLeft.current = scrollLeft + } + + return { isTop, isBottom, scrollDirection, handleScroll } +} + export function Viewport({ className, children, @@ -31,42 +95,7 @@ export function ScrollArea({ children, ...props }: React.ComponentProps) { - const [isTop, setIsTop] = useState(true) - - const [scrollDirection, setScrollDirection] = useState< - 'up' | 'down' | 'left' | 'right' | 'none' - >('none') - - const lastScrollTop = useRef(0) - const lastScrollLeft = useRef(0) - - const handleScroll = (e: React.UIEvent) => { - const target = e.currentTarget as HTMLElement - const { scrollTop, scrollLeft } = target - - setIsTop(scrollTop === 0) - - const deltaY = scrollTop - lastScrollTop.current - const deltaX = scrollLeft - lastScrollLeft.current - - // Determine primary scroll direction - if (Math.abs(deltaY) > Math.abs(deltaX)) { - if (deltaY > 0) { - setScrollDirection('down') - } else if (deltaY < 0) { - setScrollDirection('up') - } - } else if (Math.abs(deltaX) > Math.abs(deltaY)) { - if (deltaX > 0) { - setScrollDirection('right') - } else if (deltaX < 0) { - setScrollDirection('left') - } - } - - lastScrollTop.current = scrollTop - lastScrollLeft.current = scrollLeft - } + const { isTop, scrollDirection, handleScroll } = useScrollTracking() return ( {children} + @@ -119,20 +149,44 @@ export function AppContentScrollArea({ children, ...props }: React.ComponentProps) { + const viewportRef = useRef(null) + + const { isTop, isBottom, scrollDirection, handleScroll } = useScrollTracking() + return ( - - {children} - + + + {children} + + + + + + ) } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/_modules/header.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/_modules/header.tsx index b0595322c4..425c4c90e9 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/_modules/header.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/_modules/header.tsx @@ -62,7 +62,7 @@ export function MacOSHeader({ className, ...props }: ComponentProps<'div'>) { {...props} >
diff --git a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/route.tsx b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/route.tsx index 9f4cb419aa..184dcc50bc 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/route.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/pages/(experimental)/experimental/settings/route.tsx @@ -16,7 +16,7 @@ function RouteComponent() {
{!isMobile && ( @@ -24,7 +24,10 @@ function RouteComponent() { )}
{ 'h-[calc(100vh-40px-64px)]', 'sm:h-[calc(100vh-40px-48px)]', 'overflow-hidden', - 'bg-white dark:bg-black', )} data-slot="app-content" /> @@ -25,10 +24,7 @@ const AppContent = () => { function RouteComponent() { return (
{ e.preventDefault() }} diff --git a/clash-nyanpasu/frontend/ui/package.json b/clash-nyanpasu/frontend/ui/package.json index 0822cb991d..9942cafad2 100644 --- a/clash-nyanpasu/frontend/ui/package.json +++ b/clash-nyanpasu/frontend/ui/package.json @@ -20,7 +20,7 @@ "@tauri-apps/api": "2.8.0", "@types/d3": "7.4.3", "@types/react": "19.2.7", - "@vitejs/plugin-react": "5.1.1", + "@vitejs/plugin-react": "5.1.2", "ahooks": "3.9.6", "d3": "7.9.0", "framer-motion": "12.23.24", @@ -30,7 +30,7 @@ "react-i18next": "15.7.4", "react-use": "17.6.0", "tailwindcss": "4.1.17", - "vite": "7.2.4", + "vite": "7.3.0", "vite-tsconfig-paths": "5.1.4" }, "devDependencies": { diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index 5cf077e694..8809e89039 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.19.17", - "mihomo_alpha": "alpha-87c3f70", + "mihomo_alpha": "alpha-9112115", "clash_rs": "v0.9.3", "clash_premium": "2023-09-05-gdcc8d87", "clash_rs_alpha": "0.9.3-alpha+sha.a6538ac" @@ -69,5 +69,5 @@ "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" } }, - "updated_at": "2025-12-19T22:21:30.804Z" + "updated_at": "2025-12-20T22:21:16.275Z" } diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 63a6237d85..f913798930 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -222,7 +222,7 @@ importers: specifier: 11.14.1 version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.7)(react@19.2.0))(@types/react@19.2.7)(react@19.2.0) '@hookform/resolvers': - specifier: ^5.2.2 + specifier: 5.2.2 version: 5.2.2(react-hook-form@7.69.0(react@19.2.0)) '@inlang/paraglide-js': specifier: 2.7.0 @@ -261,7 +261,7 @@ importers: specifier: 2.2.6 version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-separator': - specifier: ^1.1.8 + specifier: 1.1.8 version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-slot': specifier: 1.2.4 @@ -342,7 +342,7 @@ importers: specifier: 1.6.5 version: 1.6.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react-hook-form: - specifier: ^7.69.0 + specifier: 7.69.0 version: 7.69.0(react@19.2.0) react-hook-form-mui: specifier: 8.2.0 @@ -398,7 +398,7 @@ importers: version: 1.134.15(@tanstack/react-router@1.134.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.134.15)(@types/node@24.10.4)(csstype@3.2.3)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(sass-embedded@1.93.3)(sass@1.93.3)(solid-js@1.9.5)(stylus@0.62.0)(terser@5.36.0)(tiny-invariant@1.3.3)(tsx@4.21.0)(yaml@2.8.1) '@tanstack/router-plugin': specifier: 1.134.15 - version: 1.134.15(@tanstack/react-router@1.134.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 1.134.15(@tanstack/react-router@1.134.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) '@tauri-apps/plugin-clipboard-manager': specifier: 2.3.0 version: 2.3.0 @@ -434,13 +434,13 @@ importers: version: 13.15.10 '@vitejs/plugin-legacy': specifier: 7.2.1 - version: 7.2.1(terser@5.36.0)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 7.2.1(terser@5.36.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) '@vitejs/plugin-react': - specifier: 5.1.1 - version: 5.1.1(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + specifier: 5.1.2 + version: 5.1.2(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) '@vitejs/plugin-react-swc': specifier: 4.2.2 - version: 4.2.2(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 4.2.2(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) change-case: specifier: 5.4.4 version: 5.4.4 @@ -478,20 +478,20 @@ importers: specifier: 13.15.26 version: 13.15.26 vite: - specifier: 7.2.4 - version: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + specifier: 7.3.0 + version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) vite-plugin-html: specifier: 3.2.2 - version: 3.2.2(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 3.2.2(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) vite-plugin-sass-dts: - specifier: 1.3.34 - version: 1.3.34(postcss@8.5.6)(prettier@3.7.4)(sass-embedded@1.93.3)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + specifier: 1.3.35 + version: 1.3.35(postcss@8.5.6)(prettier@3.7.4)(sass-embedded@1.93.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) vite-plugin-svgr: specifier: 4.5.0 - version: 4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) vite-tsconfig-paths: specifier: 5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) zod: specifier: 4.1.13 version: 4.1.13 @@ -526,8 +526,8 @@ importers: specifier: 19.2.7 version: 19.2.7 '@vitejs/plugin-react': - specifier: 5.1.1 - version: 5.1.1(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + specifier: 5.1.2 + version: 5.1.2(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) ahooks: specifier: 3.9.6 version: 3.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -556,11 +556,11 @@ importers: specifier: 4.1.17 version: 4.1.17 vite: - specifier: 7.2.4 - version: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + specifier: 7.3.0 + version: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: 5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) devDependencies: '@emotion/react': specifier: 11.14.0 @@ -585,7 +585,7 @@ importers: version: 5.2.0(typescript@5.9.3) vite-plugin-dts: specifier: 4.5.4 - version: 4.5.4(@types/node@24.10.4)(rollup@4.46.2)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) + version: 4.5.4(@types/node@24.10.4)(rollup@4.46.2)(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)) scripts: dependencies: @@ -1620,252 +1620,126 @@ packages: '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} - '@esbuild/aix-ppc64@0.25.0': - resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.27.2': resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.0': - resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.27.2': resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.0': - resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.27.2': resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.0': - resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.27.2': resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.0': - resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.27.2': resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.0': - resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.27.2': resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.0': - resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.27.2': resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.0': - resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.27.2': resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.0': - resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.27.2': resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.0': - resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.27.2': resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.0': - resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.27.2': resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.0': - resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.27.2': resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.0': - resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.27.2': resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.0': - resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.27.2': resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.0': - resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.27.2': resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.0': - resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.27.2': resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.0': - resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.27.2': resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.0': - resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.27.2': resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.0': - resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.27.2': resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.0': - resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.27.2': resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.0': - resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.27.2': resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} engines: {node: '>=18'} @@ -1878,48 +1752,24 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.0': - resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.27.2': resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.0': - resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.27.2': resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.0': - resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.27.2': resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.0': - resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.27.2': resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} engines: {node: '>=18'} @@ -3225,6 +3075,9 @@ packages: '@rolldown/pluginutils@1.0.0-beta.47': resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==} + '@rolldown/pluginutils@1.0.0-beta.53': + resolution: {integrity: sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==} + '@rollup/pluginutils@4.2.1': resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} engines: {node: '>= 8.0.0'} @@ -4467,8 +4320,8 @@ packages: peerDependencies: vite: ^4 || ^5 || ^6 || ^7 - '@vitejs/plugin-react@5.1.1': - resolution: {integrity: sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==} + '@vitejs/plugin-react@5.1.2': + resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 @@ -5592,11 +5445,6 @@ packages: resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} engines: {node: '>=0.12'} - esbuild@0.25.0: - resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.27.2: resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} engines: {node: '>=18'} @@ -8851,8 +8699,8 @@ packages: peerDependencies: vite: '>=2.0.0' - vite-plugin-sass-dts@1.3.34: - resolution: {integrity: sha512-+m7SJX5Jm+50IxbutY4aptEjKpAfjY4okwNe05AHDodEYr8LZY3tsIFQ/rXG12WSytYWDnipJKb6xZrvqWGckA==} + vite-plugin-sass-dts@1.3.35: + resolution: {integrity: sha512-WWfOvgwu7ljBdmtt8VjSvsyzmXUhyITdXhDYzkTprXYOJ9Efbknf97lBPbKcF2sCVeK/JsH+djvJbkazDU5VGQ==} engines: {node: '>=20'} peerDependencies: postcss: ^8 @@ -8873,8 +8721,8 @@ packages: vite: optional: true - vite@7.2.4: - resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} + vite@7.3.0: + resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -10488,156 +10336,81 @@ snapshots: '@epic-web/invariant@1.0.0': {} - '@esbuild/aix-ppc64@0.25.0': - optional: true - '@esbuild/aix-ppc64@0.27.2': optional: true - '@esbuild/android-arm64@0.25.0': - optional: true - '@esbuild/android-arm64@0.27.2': optional: true - '@esbuild/android-arm@0.25.0': - optional: true - '@esbuild/android-arm@0.27.2': optional: true - '@esbuild/android-x64@0.25.0': - optional: true - '@esbuild/android-x64@0.27.2': optional: true - '@esbuild/darwin-arm64@0.25.0': - optional: true - '@esbuild/darwin-arm64@0.27.2': optional: true - '@esbuild/darwin-x64@0.25.0': - optional: true - '@esbuild/darwin-x64@0.27.2': optional: true - '@esbuild/freebsd-arm64@0.25.0': - optional: true - '@esbuild/freebsd-arm64@0.27.2': optional: true - '@esbuild/freebsd-x64@0.25.0': - optional: true - '@esbuild/freebsd-x64@0.27.2': optional: true - '@esbuild/linux-arm64@0.25.0': - optional: true - '@esbuild/linux-arm64@0.27.2': optional: true - '@esbuild/linux-arm@0.25.0': - optional: true - '@esbuild/linux-arm@0.27.2': optional: true - '@esbuild/linux-ia32@0.25.0': - optional: true - '@esbuild/linux-ia32@0.27.2': optional: true - '@esbuild/linux-loong64@0.25.0': - optional: true - '@esbuild/linux-loong64@0.27.2': optional: true - '@esbuild/linux-mips64el@0.25.0': - optional: true - '@esbuild/linux-mips64el@0.27.2': optional: true - '@esbuild/linux-ppc64@0.25.0': - optional: true - '@esbuild/linux-ppc64@0.27.2': optional: true - '@esbuild/linux-riscv64@0.25.0': - optional: true - '@esbuild/linux-riscv64@0.27.2': optional: true - '@esbuild/linux-s390x@0.25.0': - optional: true - '@esbuild/linux-s390x@0.27.2': optional: true - '@esbuild/linux-x64@0.25.0': - optional: true - '@esbuild/linux-x64@0.27.2': optional: true - '@esbuild/netbsd-arm64@0.25.0': - optional: true - '@esbuild/netbsd-arm64@0.27.2': optional: true - '@esbuild/netbsd-x64@0.25.0': - optional: true - '@esbuild/netbsd-x64@0.27.2': optional: true - '@esbuild/openbsd-arm64@0.25.0': - optional: true - '@esbuild/openbsd-arm64@0.27.2': optional: true - '@esbuild/openbsd-x64@0.25.0': - optional: true - '@esbuild/openbsd-x64@0.27.2': optional: true '@esbuild/openharmony-arm64@0.27.2': optional: true - '@esbuild/sunos-x64@0.25.0': - optional: true - '@esbuild/sunos-x64@0.27.2': optional: true - '@esbuild/win32-arm64@0.25.0': - optional: true - '@esbuild/win32-arm64@0.27.2': optional: true - '@esbuild/win32-ia32@0.25.0': - optional: true - '@esbuild/win32-ia32@0.27.2': optional: true - '@esbuild/win32-x64@0.25.0': - optional: true - '@esbuild/win32-x64@0.27.2': optional: true @@ -11918,6 +11691,8 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.47': {} + '@rolldown/pluginutils@1.0.0-beta.53': {} + '@rollup/pluginutils@4.2.1': dependencies: estree-walker: 2.0.2 @@ -12298,7 +12073,7 @@ snapshots: '@tanstack/router-devtools-core': 1.134.15(@tanstack/router-core@1.134.15)(@types/node@24.10.4)(csstype@3.2.3)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(solid-js@1.9.5)(stylus@0.62.0)(terser@5.36.0)(tiny-invariant@1.3.3)(tsx@4.21.0)(yaml@2.8.1) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - '@tanstack/router-core' - '@types/node' @@ -12363,7 +12138,7 @@ snapshots: goober: 2.1.16(csstype@3.2.3) solid-js: 1.9.5 tiny-invariant: 1.3.3 - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) optionalDependencies: csstype: 3.2.3 transitivePeerDependencies: @@ -12392,7 +12167,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.134.15(@tanstack/react-router@1.134.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))': + '@tanstack/router-plugin@1.134.15(@tanstack/react-router@1.134.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) @@ -12410,7 +12185,7 @@ snapshots: zod: 3.25.76 optionalDependencies: '@tanstack/react-router': 1.134.15(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -12560,8 +12335,8 @@ snapshots: '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.6 @@ -13208,7 +12983,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.10.1': optional: true - '@vitejs/plugin-legacy@7.2.1(terser@5.36.0)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))': + '@vitejs/plugin-legacy@7.2.1(terser@5.36.0)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.0) @@ -13223,27 +12998,27 @@ snapshots: regenerator-runtime: 0.14.1 systemjs: 6.15.1 terser: 5.36.0 - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color - '@vitejs/plugin-react-swc@4.2.2(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))': + '@vitejs/plugin-react-swc@4.2.2(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.47 '@swc/core': 1.13.5 - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@5.1.1(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))': + '@vitejs/plugin-react@5.1.2(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.47 + '@rolldown/pluginutils': 1.0.0-beta.53 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -14597,34 +14372,6 @@ snapshots: d: 1.0.2 ext: 1.7.0 - esbuild@0.25.0: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.0 - '@esbuild/android-arm': 0.25.0 - '@esbuild/android-arm64': 0.25.0 - '@esbuild/android-x64': 0.25.0 - '@esbuild/darwin-arm64': 0.25.0 - '@esbuild/darwin-x64': 0.25.0 - '@esbuild/freebsd-arm64': 0.25.0 - '@esbuild/freebsd-x64': 0.25.0 - '@esbuild/linux-arm': 0.25.0 - '@esbuild/linux-arm64': 0.25.0 - '@esbuild/linux-ia32': 0.25.0 - '@esbuild/linux-loong64': 0.25.0 - '@esbuild/linux-mips64el': 0.25.0 - '@esbuild/linux-ppc64': 0.25.0 - '@esbuild/linux-riscv64': 0.25.0 - '@esbuild/linux-s390x': 0.25.0 - '@esbuild/linux-x64': 0.25.0 - '@esbuild/netbsd-arm64': 0.25.0 - '@esbuild/netbsd-x64': 0.25.0 - '@esbuild/openbsd-arm64': 0.25.0 - '@esbuild/openbsd-x64': 0.25.0 - '@esbuild/sunos-x64': 0.25.0 - '@esbuild/win32-arm64': 0.25.0 - '@esbuild/win32-ia32': 0.25.0 - '@esbuild/win32-x64': 0.25.0 - esbuild@0.27.2: optionalDependencies: '@esbuild/aix-ppc64': 0.27.2 @@ -18248,7 +17995,7 @@ snapshots: - rollup - supports-color - vite-plugin-dts@4.5.4(@types/node@24.10.4)(rollup@4.46.2)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): + vite-plugin-dts@4.5.4(@types/node@24.10.4)(rollup@4.46.2)(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: '@microsoft/api-extractor': 7.51.0(@types/node@24.10.4) '@rollup/pluginutils': 5.1.4(rollup@4.46.2) @@ -18261,13 +18008,13 @@ snapshots: magic-string: 0.30.17 typescript: 5.9.3 optionalDependencies: - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - rollup - supports-color - vite-plugin-html@3.2.2(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): + vite-plugin-html@3.2.2(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: '@rollup/pluginutils': 4.2.1 colorette: 2.0.20 @@ -18281,41 +18028,41 @@ snapshots: html-minifier-terser: 6.1.0 node-html-parser: 5.4.2 pathe: 0.2.0 - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) - vite-plugin-sass-dts@1.3.34(postcss@8.5.6)(prettier@3.7.4)(sass-embedded@1.93.3)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): + vite-plugin-sass-dts@1.3.35(postcss@8.5.6)(prettier@3.7.4)(sass-embedded@1.93.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: postcss: 8.5.6 postcss-js: 4.0.1(postcss@8.5.6) prettier: 3.7.4 sass-embedded: 1.93.3 - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) - vite-plugin-svgr@4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): + vite-plugin-svgr@4.5.0(rollup@4.46.2)(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: '@rollup/pluginutils': 5.2.0(rollup@4.46.2) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - rollup - supports-color - typescript - vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): + vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1)): dependencies: debug: 4.3.7 globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.9.3) optionalDependencies: - vite: 7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) + vite: 7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript - vite@7.2.4(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1): + vite@7.3.0(@types/node@24.10.4)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass-embedded@1.93.3)(sass@1.93.3)(stylus@0.62.0)(terser@5.36.0)(tsx@4.21.0)(yaml@2.8.1): dependencies: - esbuild: 0.25.0 + esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 diff --git a/filebrowser/frontend/package.json b/filebrowser/frontend/package.json index c405b2f8bc..0482dba359 100644 --- a/filebrowser/frontend/package.json +++ b/filebrowser/frontend/package.json @@ -71,5 +71,5 @@ "vite-plugin-compression2": "^2.3.1", "vue-tsc": "^3.1.3" }, - "packageManager": "pnpm@10.25.0+sha512.5e82639027af37cf832061bcc6d639c219634488e0f2baebe785028a793de7b525ffcd3f7ff574f5e9860654e098fe852ba8ac5dd5cefe1767d23a020a92f501" + "packageManager": "pnpm@10.26.1+sha512.664074abc367d2c9324fdc18037097ce0a8f126034160f709928e9e9f95d98714347044e5c3164d65bd5da6c59c6be362b107546292a8eecb7999196e5ce58fa" } diff --git a/filebrowser/frontend/pnpm-lock.yaml b/filebrowser/frontend/pnpm-lock.yaml index daa7d7f4f5..1975d743bd 100644 --- a/filebrowser/frontend/pnpm-lock.yaml +++ b/filebrowser/frontend/pnpm-lock.yaml @@ -10,13 +10,13 @@ importers: dependencies: '@chenfengyuan/vue-number-input': specifier: ^2.0.1 - version: 2.0.1(vue@3.5.25(typescript@5.9.3)) + version: 2.0.1(vue@3.5.26(typescript@5.9.3)) '@vueuse/core': specifier: ^14.0.0 - version: 14.1.0(vue@3.5.25(typescript@5.9.3)) + version: 14.1.0(vue@3.5.26(typescript@5.9.3)) '@vueuse/integrations': specifier: ^14.0.0 - version: 14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)) + version: 14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.26(typescript@5.9.3)) ace-builds: specifier: ^1.43.2 version: 1.43.5 @@ -40,7 +40,7 @@ importers: version: 4.0.0 lodash-es: specifier: ^4.17.21 - version: 4.17.21 + version: 4.17.22 marked: specifier: ^17.0.0 version: 17.0.1 @@ -52,13 +52,13 @@ importers: version: 8.0.1 pinia: specifier: ^3.0.4 - version: 3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) + version: 3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) pretty-bytes: specifier: ^7.1.0 version: 7.1.0 qrcode.vue: specifier: ^3.6.0 - version: 3.6.0(vue@3.5.25(typescript@5.9.3)) + version: 3.6.0(vue@3.5.26(typescript@5.9.3)) tus-js-client: specifier: ^4.3.1 version: 4.3.1 @@ -73,32 +73,32 @@ importers: version: 0.2.30 videojs-mobile-ui: specifier: ^1.1.1 - version: 1.1.1(video.js@8.23.4) + version: 1.1.3(video.js@8.23.4) vue: specifier: ^3.5.17 - version: 3.5.25(typescript@5.9.3) + version: 3.5.26(typescript@5.9.3) vue-final-modal: specifier: ^4.5.5 - version: 4.5.5(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.25(typescript@5.9.3)) + version: 4.5.5(@vueuse/core@14.1.0(vue@3.5.26(typescript@5.9.3)))(@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.26(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.26(typescript@5.9.3)) vue-i18n: specifier: ^11.1.10 - version: 11.2.2(vue@3.5.25(typescript@5.9.3)) + version: 11.2.7(vue@3.5.26(typescript@5.9.3)) vue-lazyload: specifier: ^3.0.0 version: 3.0.0 vue-reader: specifier: ^1.2.17 - version: 1.3.3 + version: 1.3.4 vue-router: specifier: ^4.5.1 - version: 4.6.4(vue@3.5.25(typescript@5.9.3)) + version: 4.6.4(vue@3.5.26(typescript@5.9.3)) vue-toastification: specifier: ^2.0.0-rc.5 - version: 2.0.0-rc.5(vue@3.5.25(typescript@5.9.3)) + version: 2.0.0-rc.5(vue@3.5.26(typescript@5.9.3)) devDependencies: '@intlify/unplugin-vue-i18n': specifier: ^11.0.1 - version: 11.0.3(@vue/compiler-dom@3.5.25)(eslint@9.39.2)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) + version: 11.0.3(@vue/compiler-dom@3.5.26)(eslint@9.39.2)(rollup@4.54.0)(typescript@5.9.3)(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3)) '@tsconfig/node24': specifier: ^24.0.2 version: 24.0.3 @@ -110,13 +110,13 @@ importers: version: 24.10.4 '@typescript-eslint/eslint-plugin': specifier: ^8.37.0 - version: 8.49.0(@typescript-eslint/parser@8.37.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) + version: 8.50.0(@typescript-eslint/parser@8.37.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3) '@vitejs/plugin-legacy': specifier: ^7.2.1 - version: 7.2.1(terser@5.44.1)(vite@7.2.7(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2)) + version: 7.2.1(terser@5.44.1)(vite@7.3.0(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2)) '@vitejs/plugin-vue': specifier: ^6.0.1 - version: 6.0.3(vite@7.2.7(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3)) + version: 6.0.3(vite@7.3.0(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3)) '@vue/eslint-config-prettier': specifier: ^10.2.0 version: 10.2.0(eslint@9.39.2)(prettier@3.7.4) @@ -125,7 +125,7 @@ importers: version: 14.6.0(eslint-plugin-vue@10.6.2(@typescript-eslint/parser@8.37.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(vue-eslint-parser@10.2.0(eslint@9.39.2)))(eslint@9.39.2)(typescript@5.9.3) '@vue/tsconfig': specifier: ^0.8.1 - version: 0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) + version: 0.8.1(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)) autoprefixer: specifier: ^10.4.21 version: 10.4.23(postcss@8.5.6) @@ -155,13 +155,13 @@ importers: version: 5.9.3 vite: specifier: ^7.2.2 - version: 7.2.7(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2) + version: 7.3.0(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2) vite-plugin-compression2: specifier: ^2.3.1 - version: 2.4.0(rollup@4.53.3) + version: 2.4.0(rollup@4.54.0) vue-tsc: specifier: ^3.1.3 - version: 3.1.8(typescript@5.9.3) + version: 3.2.0(typescript@5.9.3) packages: @@ -671,156 +671,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.2': + resolution: {integrity: sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.2': + resolution: {integrity: sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.2': + resolution: {integrity: sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.2': + resolution: {integrity: sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.2': + resolution: {integrity: sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.2': + resolution: {integrity: sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.2': + resolution: {integrity: sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.2': + resolution: {integrity: sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.2': + resolution: {integrity: sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.2': + resolution: {integrity: sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.2': + resolution: {integrity: sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.2': + resolution: {integrity: sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.2': + resolution: {integrity: sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.2': + resolution: {integrity: sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.2': + resolution: {integrity: sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.2': + resolution: {integrity: sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.2': + resolution: {integrity: sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.2': + resolution: {integrity: sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.2': + resolution: {integrity: sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.27.2': + resolution: {integrity: sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.2': + resolution: {integrity: sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.2': + resolution: {integrity: sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.2': + resolution: {integrity: sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.2': + resolution: {integrity: sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.2': + resolution: {integrity: sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.2': + resolution: {integrity: sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -887,18 +1043,22 @@ packages: vue-i18n: optional: true - '@intlify/core-base@11.2.2': - resolution: {integrity: sha512-0mCTBOLKIqFUP3BzwuFW23hYEl9g/wby6uY//AC5hTgQfTsM2srCYF2/hYGp+a5DZ/HIFIgKkLJMzXTt30r0JQ==} + '@intlify/core-base@11.2.7': + resolution: {integrity: sha512-+Ra9I/LAzXDnmv/IrTO03WMCiLya7pHRmGJvNl9fKwx/W4REJ0xaMk2PxCRqnxcBsX443amEMdebQ3R1geiuIw==} engines: {node: '>= 16'} - '@intlify/message-compiler@11.2.2': - resolution: {integrity: sha512-XS2p8Ff5JxWsKhgfld4/MRQzZRQ85drMMPhb7Co6Be4ZOgqJX1DzcZt0IFgGTycgqL8rkYNwgnD443Q+TapOoA==} + '@intlify/message-compiler@11.2.7': + resolution: {integrity: sha512-TFamC+GzJAotAFwUNvbtRVBgvuSn2nCwKNresmPUHv3IIVMmXJt7QQJj/DORI1h8hs46ZF6L0Fs2xBohSOE4iQ==} engines: {node: '>= 16'} '@intlify/shared@11.2.2': resolution: {integrity: sha512-OtCmyFpSXxNu/oET/aN6HtPCbZ01btXVd0f3w00YsHOb13Kverk1jzA2k47pAekM55qbUw421fvPF1yxZ+gicw==} engines: {node: '>= 16'} + '@intlify/shared@11.2.7': + resolution: {integrity: sha512-uvlkvc/0uQ4FDlHQZccpUnmcOwNcaI3i+69ck2YJ+GqM35AoVbuS63b+YfirV4G0SZh64Ij2UMcFRMmB4nr95w==} + engines: {node: '>= 16'} + '@intlify/unplugin-vue-i18n@11.0.3': resolution: {integrity: sha512-iQuik0nXfdVZ5ab+IEyBFEuvMQ213zfbUpBXaEdHPk8DV+qB2CT/SdFuDhfUDRRBZc/e0qoLlfmc9urhnRYVWw==} engines: {node: '>= 20'} @@ -977,113 +1137,113 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.53.3': - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + '@rollup/rollup-android-arm-eabi@4.54.0': + resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.53.3': - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + '@rollup/rollup-android-arm64@4.54.0': + resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.53.3': - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + '@rollup/rollup-darwin-arm64@4.54.0': + resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.53.3': - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + '@rollup/rollup-darwin-x64@4.54.0': + resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.53.3': - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + '@rollup/rollup-freebsd-arm64@4.54.0': + resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.53.3': - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + '@rollup/rollup-freebsd-x64@4.54.0': + resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + '@rollup/rollup-linux-arm-gnueabihf@4.54.0': + resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.53.3': - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + '@rollup/rollup-linux-arm-musleabihf@4.54.0': + resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.53.3': - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + '@rollup/rollup-linux-arm64-gnu@4.54.0': + resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.53.3': - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + '@rollup/rollup-linux-arm64-musl@4.54.0': + resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loong64-gnu@4.53.3': - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + '@rollup/rollup-linux-loong64-gnu@4.54.0': + resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.53.3': - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + '@rollup/rollup-linux-ppc64-gnu@4.54.0': + resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.53.3': - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + '@rollup/rollup-linux-riscv64-gnu@4.54.0': + resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.53.3': - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + '@rollup/rollup-linux-riscv64-musl@4.54.0': + resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.53.3': - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + '@rollup/rollup-linux-s390x-gnu@4.54.0': + resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.53.3': - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + '@rollup/rollup-linux-x64-gnu@4.54.0': + resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.53.3': - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + '@rollup/rollup-linux-x64-musl@4.54.0': + resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.53.3': - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + '@rollup/rollup-openharmony-arm64@4.54.0': + resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.53.3': - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + '@rollup/rollup-win32-arm64-msvc@4.54.0': + resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.53.3': - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + '@rollup/rollup-win32-ia32-msvc@4.54.0': + resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.53.3': - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + '@rollup/rollup-win32-x64-gnu@4.54.0': + resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.53.3': - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + '@rollup/rollup-win32-x64-msvc@4.54.0': + resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==} cpu: [x64] os: [win32] @@ -1123,11 +1283,11 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/eslint-plugin@8.49.0': - resolution: {integrity: sha512-JXij0vzIaTtCwu6SxTh8qBc66kmf1xs7pI4UOiMDFVct6q86G0Zs7KRcEoJgY3Cav3x5Tq0MF5jwgpgLqgKG3A==} + '@typescript-eslint/eslint-plugin@8.50.0': + resolution: {integrity: sha512-O7QnmOXYKVtPrfYzMolrCTfkezCJS9+ljLdKW/+DCvRsc3UAz+sbH6Xcsv7p30+0OwUbeWfUDAQE0vpabZ3QLg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.49.0 + '@typescript-eslint/parser': ^8.50.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' @@ -1150,6 +1310,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/project-service@8.50.0': + resolution: {integrity: sha512-Cg/nQcL1BcoTijEWyx4mkVC56r8dj44bFDvBdygifuS20f3OZCHmFbjF34DPSi07kwlFvqfv/xOLnJ5DquxSGQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/scope-manager@8.37.0': resolution: {integrity: sha512-0vGq0yiU1gbjKob2q691ybTg9JX6ShiVXAAfm2jGf3q0hdP6/BruaFjL/ManAR/lj05AvYCH+5bbVo0VtzmjOA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1158,6 +1324,10 @@ packages: resolution: {integrity: sha512-npgS3zi+/30KSOkXNs0LQXtsg9ekZ8OISAOLGWA/ZOEn0ZH74Ginfl7foziV8DT+D98WfQ5Kopwqb/PZOaIJGg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.50.0': + resolution: {integrity: sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.37.0': resolution: {integrity: sha512-1/YHvAVTimMM9mmlPvTec9NP4bobA1RkDbMydxG8omqwJJLEW/Iy2C4adsAESIXU3WGLXFHSZUU+C9EoFWl4Zg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1170,6 +1340,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/tsconfig-utils@8.50.0': + resolution: {integrity: sha512-vxd3G/ybKTSlm31MOA96gqvrRGv9RJ7LGtZCn2Vrc5htA0zCDvcMqUkifcjrWNNKXHUU3WCkYOzzVSFBd0wa2w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/type-utils@8.37.0': resolution: {integrity: sha512-SPkXWIkVZxhgwSwVq9rqj/4VFo7MnWwVaRNznfQDc/xPYHjXnPfLWn+4L6FF1cAz6e7dsqBeMawgl7QjUMj4Ow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1177,8 +1353,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/type-utils@8.49.0': - resolution: {integrity: sha512-KTExJfQ+svY8I10P4HdxKzWsvtVnsuCifU5MvXrRwoP2KOlNZ9ADNEWWsQTJgMxLzS5VLQKDjkCT/YzgsnqmZg==} + '@typescript-eslint/type-utils@8.50.0': + resolution: {integrity: sha512-7OciHT2lKCewR0mFoBrvZJ4AXTMe/sYOe87289WAViOocEmDjjv8MvIOT2XESuKj9jp8u3SZYUSh89QA4S1kQw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1192,6 +1368,10 @@ packages: resolution: {integrity: sha512-e9k/fneezorUo6WShlQpMxXh8/8wfyc+biu6tnAqA81oWrEic0k21RHzP9uqqpyBBeBKu4T+Bsjy9/b8u7obXQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.50.0': + resolution: {integrity: sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.37.0': resolution: {integrity: sha512-zuWDMDuzMRbQOM+bHyU4/slw27bAUEcKSKKs3hcv2aNnc/tvE/h7w60dwVw8vnal2Pub6RT1T7BI8tFZ1fE+yg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1204,6 +1384,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/typescript-estree@8.50.0': + resolution: {integrity: sha512-W7SVAGBR/IX7zm1t70Yujpbk+zdPq/u4soeFSknWFdXIFuWsBGBOUu/Tn/I6KHSKvSh91OiMuaSnYp3mtPt5IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/utils@8.37.0': resolution: {integrity: sha512-TSFvkIW6gGjN2p6zbXo20FzCABbyUAuq6tBvNRGsKdsSQ6a7rnV6ADfZ7f4iI3lIiXc4F4WWvtUfDw9CJ9pO5A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1211,8 +1397,8 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.9.0' - '@typescript-eslint/utils@8.49.0': - resolution: {integrity: sha512-N3W7rJw7Rw+z1tRsHZbK395TWSYvufBXumYtEGzypgMUthlg0/hmCImeA8hgO2d2G4pd7ftpxxul2J8OdtdaFA==} + '@typescript-eslint/utils@8.50.0': + resolution: {integrity: sha512-87KgUXET09CRjGCi2Ejxy3PULXna63/bMYv72tCAlDJC3Yqwln0HiFJ3VJMst2+mEtNtZu5oFvX4qJGjKsnAgg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1226,6 +1412,10 @@ packages: resolution: {integrity: sha512-LlKaciDe3GmZFphXIc79THF/YYBugZ7FS1pO581E/edlVVNbZKDy93evqmrfQ9/Y4uN0vVhX4iuchq26mK/iiA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.50.0': + resolution: {integrity: sha512-Xzmnb58+Db78gT/CCj/PVCvK+zxbnsw6F+O1oheYszJbBSdEjVhQi3C/Xttzxgi/GLmpvOggRs1RFpiJ8+c34Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@videojs/http-streaming@3.17.2': resolution: {integrity: sha512-VBQ3W4wnKnVKb/limLdtSD2rAd5cmHN70xoMf4OmuDd0t2kfJX04G+sfw6u2j8oOm2BXYM9E1f4acHruqKnM1g==} engines: {node: '>=8', npm: '>=5'} @@ -1253,26 +1443,26 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 vue: ^3.2.25 - '@volar/language-core@2.4.26': - resolution: {integrity: sha512-hH0SMitMxnB43OZpyF1IFPS9bgb2I3bpCh76m2WEK7BE0A0EzpYsRp0CCH2xNKshr7kacU5TQBLYn4zj7CG60A==} + '@volar/language-core@2.4.27': + resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==} - '@volar/source-map@2.4.26': - resolution: {integrity: sha512-JJw0Tt/kSFsIRmgTQF4JSt81AUSI1aEye5Zl65EeZ8H35JHnTvFGmpDOBn5iOxd48fyGE+ZvZBp5FcgAy/1Qhw==} + '@volar/source-map@2.4.27': + resolution: {integrity: sha512-ynlcBReMgOZj2i6po+qVswtDUeeBRCTgDurjMGShbm8WYZgJ0PA4RmtebBJ0BCYol1qPv3GQF6jK7C9qoVc7lg==} - '@volar/typescript@2.4.26': - resolution: {integrity: sha512-N87ecLD48Sp6zV9zID/5yuS1+5foj0DfuYGdQ6KHj/IbKvyKv1zNX6VCmnKYwtmHadEO6mFc2EKISiu3RDPAvA==} + '@volar/typescript@2.4.27': + resolution: {integrity: sha512-eWaYCcl/uAPInSK2Lze6IqVWaBu/itVqR5InXcHXFyles4zO++Mglt3oxdgj75BDcv1Knr9Y93nowS8U3wqhxg==} - '@vue/compiler-core@3.5.25': - resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} + '@vue/compiler-core@3.5.26': + resolution: {integrity: sha512-vXyI5GMfuoBCnv5ucIT7jhHKl55Y477yxP6fc4eUswjP8FG3FFVFd41eNDArR+Uk3QKn2Z85NavjaxLxOC19/w==} - '@vue/compiler-dom@3.5.25': - resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} + '@vue/compiler-dom@3.5.26': + resolution: {integrity: sha512-y1Tcd3eXs834QjswshSilCBnKGeQjQXB6PqFn/1nxcQw4pmG42G8lwz+FZPAZAby6gZeHSt/8LMPfZ4Rb+Bd/A==} - '@vue/compiler-sfc@3.5.25': - resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} + '@vue/compiler-sfc@3.5.26': + resolution: {integrity: sha512-egp69qDTSEZcf4bGOSsprUr4xI73wfrY5oRs6GSgXFTiHrWj4Y3X5Ydtip9QMqiCMCPVwLglB9GBxXtTadJ3mA==} - '@vue/compiler-ssr@3.5.25': - resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} + '@vue/compiler-ssr@3.5.26': + resolution: {integrity: sha512-lZT9/Y0nSIRUPVvapFJEVDbEXruZh2IYHMk2zTtEgJSlP5gVOqeWXH54xDKAaFS4rTnDeDBQUYDtxKyoW9FwDw==} '@vue/devtools-api@6.6.4': resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} @@ -1303,30 +1493,25 @@ packages: typescript: optional: true - '@vue/language-core@3.1.8': - resolution: {integrity: sha512-PfwAW7BLopqaJbneChNL6cUOTL3GL+0l8paYP5shhgY5toBNidWnMXWM+qDwL7MC9+zDtzCF2enT8r6VPu64iw==} + '@vue/language-core@3.2.0': + resolution: {integrity: sha512-CHIuDtZ04CIElAgEuLbwmq3p7QcmYoVPmBPqtdvWJCflZE5W3KHT/5DRBvDv1r2TteCjN02uYHiaAEWq9hQNiA==} + + '@vue/reactivity@3.5.26': + resolution: {integrity: sha512-9EnYB1/DIiUYYnzlnUBgwU32NNvLp/nhxLXeWRhHUEeWNTn1ECxX8aGO7RTXeX6PPcxe3LLuNBFoJbV4QZ+CFQ==} + + '@vue/runtime-core@3.5.26': + resolution: {integrity: sha512-xJWM9KH1kd201w5DvMDOwDHYhrdPTrAatn56oB/LRG4plEQeZRQLw0Bpwih9KYoqmzaxF0OKSn6swzYi84e1/Q==} + + '@vue/runtime-dom@3.5.26': + resolution: {integrity: sha512-XLLd/+4sPC2ZkN/6+V4O4gjJu6kSDbHAChvsyWgm1oGbdSO3efvGYnm25yCjtFm/K7rrSDvSfPDgN1pHgS4VNQ==} + + '@vue/server-renderer@3.5.26': + resolution: {integrity: sha512-TYKLXmrwWKSodyVuO1WAubucd+1XlLg4set0YoV+Hu8Lo79mp/YMwWV5mC5FgtsDxX3qo1ONrxFaTP1OQgy1uA==} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + vue: 3.5.26 - '@vue/reactivity@3.5.25': - resolution: {integrity: sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==} - - '@vue/runtime-core@3.5.25': - resolution: {integrity: sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==} - - '@vue/runtime-dom@3.5.25': - resolution: {integrity: sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==} - - '@vue/server-renderer@3.5.25': - resolution: {integrity: sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==} - peerDependencies: - vue: 3.5.25 - - '@vue/shared@3.5.25': - resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} + '@vue/shared@3.5.26': + resolution: {integrity: sha512-7Z6/y3uFI5PRoKeorTOSXKcDj0MSasfNNltcslbFrPpcw6aXRUALq4IfJlaTRspiWIUOEZbrpM+iQGmCOiWe4A==} '@vue/tsconfig@0.8.1': resolution: {integrity: sha512-aK7feIWPXFSUhsCP9PFqPyFOcz4ENkb8hZ2pneL6m2UjCkccvaOhC/5KCKluuBufvp2KzkbdA2W2pk20vLzu3g==} @@ -1593,8 +1778,8 @@ packages: electron-to-chromium@1.5.267: resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + entities@7.0.0: + resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==} engines: {node: '>=0.12'} epubjs@0.3.93: @@ -1616,6 +1801,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.2: + resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -1943,8 +2133,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash-es@4.17.22: + resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} lodash._baseiteratee@4.7.0: resolution: {integrity: sha512-nqB9M+wITz0BX/Q2xg6fQ8mLkyfF7MU7eE+MNBNjTHFKeKaZAPEzEg+E8LWxKWf1DQVflNEn9N49yAuqKh2mWQ==} @@ -2225,8 +2415,8 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + rollup@4.54.0: + resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2410,8 +2600,8 @@ packages: videojs-hotkeys@0.2.30: resolution: {integrity: sha512-G8kEQZPapoWDoEajh2Nroy4bCN1qVEul5AuzZqBS7ZCG45K7hqTYKgf1+fmYvG8m8u84sZmVMUvSWZBjaFW66Q==} - videojs-mobile-ui@1.1.1: - resolution: {integrity: sha512-q7vx74++bqu2763Tc/GG4qFcMt42emC8uXe/z+zFVpBIiysgAf89AgorE6m30YHWtVJWgbRIyzFVYNOxCk9qow==} + videojs-mobile-ui@1.1.3: + resolution: {integrity: sha512-LyWIRZBQWRouUQ9i9HBBvhwFL1uZkg3Adt52nT+e297dwpOgTaELO7gCXgvj5f6a2AfEb8a5AQMY4SLeIf8cqw==} engines: {node: '>=14', npm: '>=6'} peerDependencies: video.js: ^8 @@ -2422,8 +2612,8 @@ packages: vite-plugin-compression2@2.4.0: resolution: {integrity: sha512-8J4CBF1+dM1I06azba/eXJuJHinLF0Am7lUvRH8AZpu0otJoBaDEnxrIEr5iPZJSwH0AEglJGYCveh7pN52jCg==} - vite@7.2.7: - resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} + vite@7.3.0: + resolution: {integrity: sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2479,8 +2669,8 @@ packages: focus-trap: '>=7.2.0' vue: '>=3.2.0' - vue-i18n@11.2.2: - resolution: {integrity: sha512-ULIKZyRluUPRCZmihVgUvpq8hJTtOqnbGZuv4Lz+byEKZq4mU0g92og414l6f/4ju+L5mORsiUuEPYrAuX2NJg==} + vue-i18n@11.2.7: + resolution: {integrity: sha512-LPv8bAY5OA0UvFEXl4vBQOBqJzRrlExy92tWgRuwW7tbykHf7CH71G2Y4TM2OwGcIS4+hyqKHS2EVBqaYwPY9Q==} engines: {node: '>= 16'} peerDependencies: vue: ^3.0.0 @@ -2488,8 +2678,8 @@ packages: vue-lazyload@3.0.0: resolution: {integrity: sha512-h2keL/Rj550dLgesgOtXJS9qOiSMmuJNeVlfNAYV1/IYwOQYaWk5mFJlwRxmZDK9YC5gECcFLYYj7z1lKSf9ug==} - vue-reader@1.3.3: - resolution: {integrity: sha512-Rpd9szXrnlyK1TxBsy/5He8W077ALFxrDLzOiD6HIzsJNj4miKs6nDljj4HdSliKbZ7LYvUMOitW9TL+5J5Ecg==} + vue-reader@1.3.4: + resolution: {integrity: sha512-QYTX9hlrV71gL/1vMejcBLLS9Ool29XMZcLQwvL0Ep1F//o0ymzYbKX2Lre+4BUBkVq49/GmmGCmAJACsJL9tw==} vue-router@4.6.4: resolution: {integrity: sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==} @@ -2501,14 +2691,14 @@ packages: peerDependencies: vue: ^3.0.2 - vue-tsc@3.1.8: - resolution: {integrity: sha512-deKgwx6exIHeZwF601P1ktZKNF0bepaSN4jBU3AsbldPx9gylUc1JDxYppl82yxgkAgaz0Y0LCLOi+cXe9HMYA==} + vue-tsc@3.2.0: + resolution: {integrity: sha512-NFhcKKQZeTuG8/gc8XwFANx/lC0Dd3dCZ97TWh1a63PcD22KkFy4QLeT8JMtduaQT1NzySWmx3qXm16Hj1Xsxg==} hasBin: true peerDependencies: typescript: '>=5.0.0' - vue@3.5.25: - resolution: {integrity: sha512-YLVdgv2K13WJ6n+kD5owehKtEXwdwXuj2TTyJMsO7pSeKw2bfRNZGjhB7YzrpbMYj5b5QsUebHpOqR3R3ziy/g==} + vue@3.5.26: + resolution: {integrity: sha512-SJ/NTccVyAoNUJmkM9KUqPcYlY+u8OVL1X5EW9RIs3ch5H2uERxyyIUI4MRxVCSOiEcupX9xNGde1tL9ZKpimA==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -3203,88 +3393,166 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@chenfengyuan/vue-number-input@2.0.1(vue@3.5.25(typescript@5.9.3))': + '@chenfengyuan/vue-number-input@2.0.1(vue@3.5.26(typescript@5.9.3))': dependencies: - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.27.2': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.27.2': + optional: true + '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.27.2': + optional: true + '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.27.2': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.27.2': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.27.2': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.27.2': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.27.2': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.27.2': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.27.2': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.27.2': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.27.2': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.27.2': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.27.2': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.27.2': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.27.2': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.27.2': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.27.2': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.27.2': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.27.2': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.27.2': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.27.2': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.27.2': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.27.2': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.27.2': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true + '@esbuild/win32-x64@0.27.2': + optional: true + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.2)': dependencies: eslint: 9.39.2 @@ -3342,9 +3610,9 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} - '@intlify/bundle-utils@11.0.3(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))': + '@intlify/bundle-utils@11.0.3(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))': dependencies: - '@intlify/message-compiler': 11.2.2 + '@intlify/message-compiler': 11.2.7 '@intlify/shared': 11.2.2 acorn: 8.15.0 esbuild: 0.25.12 @@ -3354,27 +3622,29 @@ snapshots: source-map-js: 1.2.1 yaml-eslint-parser: 1.3.2 optionalDependencies: - vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3)) + vue-i18n: 11.2.7(vue@3.5.26(typescript@5.9.3)) - '@intlify/core-base@11.2.2': + '@intlify/core-base@11.2.7': dependencies: - '@intlify/message-compiler': 11.2.2 - '@intlify/shared': 11.2.2 + '@intlify/message-compiler': 11.2.7 + '@intlify/shared': 11.2.7 - '@intlify/message-compiler@11.2.2': + '@intlify/message-compiler@11.2.7': dependencies: - '@intlify/shared': 11.2.2 + '@intlify/shared': 11.2.7 source-map-js: 1.2.1 '@intlify/shared@11.2.2': {} - '@intlify/unplugin-vue-i18n@11.0.3(@vue/compiler-dom@3.5.25)(eslint@9.39.2)(rollup@4.53.3)(typescript@5.9.3)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))': + '@intlify/shared@11.2.7': {} + + '@intlify/unplugin-vue-i18n@11.0.3(@vue/compiler-dom@3.5.26)(eslint@9.39.2)(rollup@4.54.0)(typescript@5.9.3)(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3))': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2) - '@intlify/bundle-utils': 11.0.3(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3))) + '@intlify/bundle-utils': 11.0.3(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3))) '@intlify/shared': 11.2.2 - '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.2.2)(@vue/compiler-dom@3.5.25)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3)) - '@rollup/pluginutils': 5.3.0(rollup@4.53.3) + '@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.2.2)(@vue/compiler-dom@3.5.26)(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3)) + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) '@typescript-eslint/scope-manager': 8.49.0 '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) debug: 4.4.3 @@ -3382,9 +3652,9 @@ snapshots: pathe: 2.0.3 picocolors: 1.1.1 unplugin: 2.3.11 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) optionalDependencies: - vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3)) + vue-i18n: 11.2.7(vue@3.5.26(typescript@5.9.3)) transitivePeerDependencies: - '@vue/compiler-dom' - eslint @@ -3392,14 +3662,14 @@ snapshots: - supports-color - typescript - '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.2.2)(@vue/compiler-dom@3.5.25)(vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)))(vue@3.5.25(typescript@5.9.3))': + '@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.2.2)(@vue/compiler-dom@3.5.26)(vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)))(vue@3.5.26(typescript@5.9.3))': dependencies: '@babel/parser': 7.28.5 optionalDependencies: '@intlify/shared': 11.2.2 - '@vue/compiler-dom': 3.5.25 - vue: 3.5.25(typescript@5.9.3) - vue-i18n: 11.2.2(vue@3.5.25(typescript@5.9.3)) + '@vue/compiler-dom': 3.5.26 + vue: 3.5.26(typescript@5.9.3) + vue-i18n: 11.2.7(vue@3.5.26(typescript@5.9.3)) '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -3441,78 +3711,78 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.53': {} - '@rollup/pluginutils@5.3.0(rollup@4.53.3)': + '@rollup/pluginutils@5.3.0(rollup@4.54.0)': dependencies: '@types/estree': 1.0.8 estree-walker: 2.0.2 picomatch: 4.0.3 optionalDependencies: - rollup: 4.53.3 + rollup: 4.54.0 - '@rollup/rollup-android-arm-eabi@4.53.3': + '@rollup/rollup-android-arm-eabi@4.54.0': optional: true - '@rollup/rollup-android-arm64@4.53.3': + '@rollup/rollup-android-arm64@4.54.0': optional: true - '@rollup/rollup-darwin-arm64@4.53.3': + '@rollup/rollup-darwin-arm64@4.54.0': optional: true - '@rollup/rollup-darwin-x64@4.53.3': + '@rollup/rollup-darwin-x64@4.54.0': optional: true - '@rollup/rollup-freebsd-arm64@4.53.3': + '@rollup/rollup-freebsd-arm64@4.54.0': optional: true - '@rollup/rollup-freebsd-x64@4.53.3': + '@rollup/rollup-freebsd-x64@4.54.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + '@rollup/rollup-linux-arm-gnueabihf@4.54.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.53.3': + '@rollup/rollup-linux-arm-musleabihf@4.54.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.53.3': + '@rollup/rollup-linux-arm64-gnu@4.54.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.53.3': + '@rollup/rollup-linux-arm64-musl@4.54.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.53.3': + '@rollup/rollup-linux-loong64-gnu@4.54.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.53.3': + '@rollup/rollup-linux-ppc64-gnu@4.54.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.53.3': + '@rollup/rollup-linux-riscv64-gnu@4.54.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.53.3': + '@rollup/rollup-linux-riscv64-musl@4.54.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.53.3': + '@rollup/rollup-linux-s390x-gnu@4.54.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.53.3': + '@rollup/rollup-linux-x64-gnu@4.54.0': optional: true - '@rollup/rollup-linux-x64-musl@4.53.3': + '@rollup/rollup-linux-x64-musl@4.54.0': optional: true - '@rollup/rollup-openharmony-arm64@4.53.3': + '@rollup/rollup-openharmony-arm64@4.54.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.53.3': + '@rollup/rollup-win32-arm64-msvc@4.54.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.53.3': + '@rollup/rollup-win32-ia32-msvc@4.54.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.53.3': + '@rollup/rollup-win32-x64-gnu@4.54.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.53.3': + '@rollup/rollup-win32-x64-msvc@4.54.0': optional: true '@tsconfig/node24@24.0.3': {} @@ -3557,14 +3827,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.37.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.50.0(@typescript-eslint/parser@8.37.0(eslint@9.39.2)(typescript@5.9.3))(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 '@typescript-eslint/parser': 8.37.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/type-utils': 8.49.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/utils': 8.49.0(eslint@9.39.2)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.49.0 + '@typescript-eslint/scope-manager': 8.50.0 + '@typescript-eslint/type-utils': 8.50.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.50.0 eslint: 9.39.2 ignore: 7.0.5 natural-compare: 1.4.0 @@ -3603,6 +3873,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.50.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@5.9.3) + '@typescript-eslint/types': 8.50.0 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.37.0': dependencies: '@typescript-eslint/types': 8.37.0 @@ -3613,6 +3892,11 @@ snapshots: '@typescript-eslint/types': 8.49.0 '@typescript-eslint/visitor-keys': 8.49.0 + '@typescript-eslint/scope-manager@8.50.0': + dependencies: + '@typescript-eslint/types': 8.50.0 + '@typescript-eslint/visitor-keys': 8.50.0 + '@typescript-eslint/tsconfig-utils@8.37.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 @@ -3621,6 +3905,10 @@ snapshots: dependencies: typescript: 5.9.3 + '@typescript-eslint/tsconfig-utils@8.50.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@typescript-eslint/type-utils@8.37.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.37.0 @@ -3633,11 +3921,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.49.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.50.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.49.0(eslint@9.39.2)(typescript@5.9.3) + '@typescript-eslint/types': 8.50.0 + '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.50.0(eslint@9.39.2)(typescript@5.9.3) debug: 4.4.3 eslint: 9.39.2 ts-api-utils: 2.1.0(typescript@5.9.3) @@ -3649,6 +3937,8 @@ snapshots: '@typescript-eslint/types@8.49.0': {} + '@typescript-eslint/types@8.50.0': {} + '@typescript-eslint/typescript-estree@8.37.0(typescript@5.9.3)': dependencies: '@typescript-eslint/project-service': 8.37.0(typescript@5.9.3) @@ -3680,6 +3970,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.50.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.50.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.50.0(typescript@5.9.3) + '@typescript-eslint/types': 8.50.0 + '@typescript-eslint/visitor-keys': 8.50.0 + debug: 4.4.3 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.37.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2) @@ -3691,12 +3996,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.49.0(eslint@9.39.2)(typescript@5.9.3)': + '@typescript-eslint/utils@8.50.0(eslint@9.39.2)(typescript@5.9.3)': dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.2) - '@typescript-eslint/scope-manager': 8.49.0 - '@typescript-eslint/types': 8.49.0 - '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.50.0 + '@typescript-eslint/types': 8.50.0 + '@typescript-eslint/typescript-estree': 8.50.0(typescript@5.9.3) eslint: 9.39.2 typescript: 5.9.3 transitivePeerDependencies: @@ -3712,6 +4017,11 @@ snapshots: '@typescript-eslint/types': 8.49.0 eslint-visitor-keys: 4.2.1 + '@typescript-eslint/visitor-keys@8.50.0': + dependencies: + '@typescript-eslint/types': 8.50.0 + eslint-visitor-keys: 4.2.1 + '@videojs/http-streaming@3.17.2(video.js@8.23.4)': dependencies: '@babel/runtime': 7.28.4 @@ -3734,7 +4044,7 @@ snapshots: global: 4.4.0 is-function: 1.0.2 - '@vitejs/plugin-legacy@7.2.1(terser@5.44.1)(vite@7.2.7(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2))': + '@vitejs/plugin-legacy@7.2.1(terser@5.44.1)(vite@7.3.0(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5) @@ -3749,57 +4059,57 @@ snapshots: regenerator-runtime: 0.14.1 systemjs: 6.15.1 terser: 5.44.1 - vite: 7.2.7(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2) + vite: 7.3.0(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@6.0.3(vite@7.2.7(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.25(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.3(vite@7.3.0(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.26(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.53 - vite: 7.2.7(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2) - vue: 3.5.25(typescript@5.9.3) + vite: 7.3.0(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2) + vue: 3.5.26(typescript@5.9.3) - '@volar/language-core@2.4.26': + '@volar/language-core@2.4.27': dependencies: - '@volar/source-map': 2.4.26 + '@volar/source-map': 2.4.27 - '@volar/source-map@2.4.26': {} + '@volar/source-map@2.4.27': {} - '@volar/typescript@2.4.26': + '@volar/typescript@2.4.27': dependencies: - '@volar/language-core': 2.4.26 + '@volar/language-core': 2.4.27 path-browserify: 1.0.1 vscode-uri: 3.1.0 - '@vue/compiler-core@3.5.25': + '@vue/compiler-core@3.5.26': dependencies: '@babel/parser': 7.28.5 - '@vue/shared': 3.5.25 - entities: 4.5.0 + '@vue/shared': 3.5.26 + entities: 7.0.0 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.25': + '@vue/compiler-dom@3.5.26': dependencies: - '@vue/compiler-core': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/compiler-core': 3.5.26 + '@vue/shared': 3.5.26 - '@vue/compiler-sfc@3.5.25': + '@vue/compiler-sfc@3.5.26': dependencies: '@babel/parser': 7.28.5 - '@vue/compiler-core': 3.5.25 - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/compiler-core': 3.5.26 + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-ssr': 3.5.26 + '@vue/shared': 3.5.26 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.6 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.25': + '@vue/compiler-ssr@3.5.26': dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/compiler-dom': 3.5.26 + '@vue/shared': 3.5.26 '@vue/devtools-api@6.6.4': {} @@ -3843,68 +4153,66 @@ snapshots: transitivePeerDependencies: - supports-color - '@vue/language-core@3.1.8(typescript@5.9.3)': + '@vue/language-core@3.2.0': dependencies: - '@volar/language-core': 2.4.26 - '@vue/compiler-dom': 3.5.25 - '@vue/shared': 3.5.25 + '@volar/language-core': 2.4.27 + '@vue/compiler-dom': 3.5.26 + '@vue/shared': 3.5.26 alien-signals: 3.1.1 muggle-string: 0.4.1 path-browserify: 1.0.1 picomatch: 4.0.3 - optionalDependencies: - typescript: 5.9.3 - '@vue/reactivity@3.5.25': + '@vue/reactivity@3.5.26': dependencies: - '@vue/shared': 3.5.25 + '@vue/shared': 3.5.26 - '@vue/runtime-core@3.5.25': + '@vue/runtime-core@3.5.26': dependencies: - '@vue/reactivity': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/reactivity': 3.5.26 + '@vue/shared': 3.5.26 - '@vue/runtime-dom@3.5.25': + '@vue/runtime-dom@3.5.26': dependencies: - '@vue/reactivity': 3.5.25 - '@vue/runtime-core': 3.5.25 - '@vue/shared': 3.5.25 + '@vue/reactivity': 3.5.26 + '@vue/runtime-core': 3.5.26 + '@vue/shared': 3.5.26 csstype: 3.2.3 - '@vue/server-renderer@3.5.25(vue@3.5.25(typescript@5.9.3))': + '@vue/server-renderer@3.5.26(vue@3.5.26(typescript@5.9.3))': dependencies: - '@vue/compiler-ssr': 3.5.25 - '@vue/shared': 3.5.25 - vue: 3.5.25(typescript@5.9.3) + '@vue/compiler-ssr': 3.5.26 + '@vue/shared': 3.5.26 + vue: 3.5.26(typescript@5.9.3) - '@vue/shared@3.5.25': {} + '@vue/shared@3.5.26': {} - '@vue/tsconfig@0.8.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3))': + '@vue/tsconfig@0.8.1(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3))': optionalDependencies: typescript: 5.9.3 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) - '@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3))': + '@vueuse/core@14.1.0(vue@3.5.26(typescript@5.9.3))': dependencies: '@types/web-bluetooth': 0.0.21 '@vueuse/metadata': 14.1.0 - '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) - vue: 3.5.25(typescript@5.9.3) + '@vueuse/shared': 14.1.0(vue@3.5.26(typescript@5.9.3)) + vue: 3.5.26(typescript@5.9.3) - '@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3))': + '@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.26(typescript@5.9.3))': dependencies: - '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) - '@vueuse/shared': 14.1.0(vue@3.5.25(typescript@5.9.3)) - vue: 3.5.25(typescript@5.9.3) + '@vueuse/core': 14.1.0(vue@3.5.26(typescript@5.9.3)) + '@vueuse/shared': 14.1.0(vue@3.5.26(typescript@5.9.3)) + vue: 3.5.26(typescript@5.9.3) optionalDependencies: focus-trap: 7.6.2 jwt-decode: 4.0.0 '@vueuse/metadata@14.1.0': {} - '@vueuse/shared@14.1.0(vue@3.5.25(typescript@5.9.3))': + '@vueuse/shared@14.1.0(vue@3.5.26(typescript@5.9.3))': dependencies: - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) '@xmldom/xmldom@0.7.13': {} @@ -4094,7 +4402,7 @@ snapshots: electron-to-chromium@1.5.267: {} - entities@4.5.0: {} + entities@7.0.0: {} epubjs@0.3.93: dependencies: @@ -4155,6 +4463,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.2 + '@esbuild/android-arm': 0.27.2 + '@esbuild/android-arm64': 0.27.2 + '@esbuild/android-x64': 0.27.2 + '@esbuild/darwin-arm64': 0.27.2 + '@esbuild/darwin-x64': 0.27.2 + '@esbuild/freebsd-arm64': 0.27.2 + '@esbuild/freebsd-x64': 0.27.2 + '@esbuild/linux-arm': 0.27.2 + '@esbuild/linux-arm64': 0.27.2 + '@esbuild/linux-ia32': 0.27.2 + '@esbuild/linux-loong64': 0.27.2 + '@esbuild/linux-mips64el': 0.27.2 + '@esbuild/linux-ppc64': 0.27.2 + '@esbuild/linux-riscv64': 0.27.2 + '@esbuild/linux-s390x': 0.27.2 + '@esbuild/linux-x64': 0.27.2 + '@esbuild/netbsd-arm64': 0.27.2 + '@esbuild/netbsd-x64': 0.27.2 + '@esbuild/openbsd-arm64': 0.27.2 + '@esbuild/openbsd-x64': 0.27.2 + '@esbuild/openharmony-arm64': 0.27.2 + '@esbuild/sunos-x64': 0.27.2 + '@esbuild/win32-arm64': 0.27.2 + '@esbuild/win32-ia32': 0.27.2 + '@esbuild/win32-x64': 0.27.2 + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} @@ -4467,7 +4804,7 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.21: {} + lodash-es@4.17.22: {} lodash._baseiteratee@4.7.0: dependencies: @@ -4617,10 +4954,10 @@ snapshots: picomatch@4.0.3: {} - pinia@3.0.4(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)): + pinia@3.0.4(typescript@5.9.3)(vue@3.5.26(typescript@5.9.3)): dependencies: '@vue/devtools-api': 7.7.8 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) optionalDependencies: typescript: 5.9.3 @@ -4663,9 +5000,9 @@ snapshots: punycode@2.3.1: {} - qrcode.vue@3.6.0(vue@3.5.25(typescript@5.9.3)): + qrcode.vue@3.6.0(vue@3.5.26(typescript@5.9.3)): dependencies: - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) querystringify@2.2.0: {} @@ -4720,32 +5057,32 @@ snapshots: rfdc@1.4.1: {} - rollup@4.53.3: + rollup@4.54.0: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 + '@rollup/rollup-android-arm-eabi': 4.54.0 + '@rollup/rollup-android-arm64': 4.54.0 + '@rollup/rollup-darwin-arm64': 4.54.0 + '@rollup/rollup-darwin-x64': 4.54.0 + '@rollup/rollup-freebsd-arm64': 4.54.0 + '@rollup/rollup-freebsd-x64': 4.54.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.54.0 + '@rollup/rollup-linux-arm-musleabihf': 4.54.0 + '@rollup/rollup-linux-arm64-gnu': 4.54.0 + '@rollup/rollup-linux-arm64-musl': 4.54.0 + '@rollup/rollup-linux-loong64-gnu': 4.54.0 + '@rollup/rollup-linux-ppc64-gnu': 4.54.0 + '@rollup/rollup-linux-riscv64-gnu': 4.54.0 + '@rollup/rollup-linux-riscv64-musl': 4.54.0 + '@rollup/rollup-linux-s390x-gnu': 4.54.0 + '@rollup/rollup-linux-x64-gnu': 4.54.0 + '@rollup/rollup-linux-x64-musl': 4.54.0 + '@rollup/rollup-openharmony-arm64': 4.54.0 + '@rollup/rollup-win32-arm64-msvc': 4.54.0 + '@rollup/rollup-win32-ia32-msvc': 4.54.0 + '@rollup/rollup-win32-x64-gnu': 4.54.0 + '@rollup/rollup-win32-x64-msvc': 4.54.0 fsevents: 2.3.3 run-parallel@1.2.0: @@ -4925,7 +5262,7 @@ snapshots: videojs-hotkeys@0.2.30: {} - videojs-mobile-ui@1.1.1(video.js@8.23.4): + videojs-mobile-ui@1.1.3(video.js@8.23.4): dependencies: global: 4.4.0 video.js: 8.23.4 @@ -4934,20 +5271,20 @@ snapshots: dependencies: global: 4.4.0 - vite-plugin-compression2@2.4.0(rollup@4.53.3): + vite-plugin-compression2@2.4.0(rollup@4.54.0): dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.53.3) + '@rollup/pluginutils': 5.3.0(rollup@4.54.0) tar-mini: 0.2.0 transitivePeerDependencies: - rollup - vite@7.2.7(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2): + vite@7.3.0(@types/node@24.10.4)(terser@5.44.1)(yaml@2.8.2): dependencies: - esbuild: 0.25.12 + esbuild: 0.27.2 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.53.3 + rollup: 4.54.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.10.4 @@ -4969,48 +5306,48 @@ snapshots: transitivePeerDependencies: - supports-color - vue-final-modal@4.5.5(@vueuse/core@14.1.0(vue@3.5.25(typescript@5.9.3)))(@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.25(typescript@5.9.3)): + vue-final-modal@4.5.5(@vueuse/core@14.1.0(vue@3.5.26(typescript@5.9.3)))(@vueuse/integrations@14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.26(typescript@5.9.3)))(focus-trap@7.6.2)(vue@3.5.26(typescript@5.9.3)): dependencies: - '@vueuse/core': 14.1.0(vue@3.5.25(typescript@5.9.3)) - '@vueuse/integrations': 14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.25(typescript@5.9.3)) + '@vueuse/core': 14.1.0(vue@3.5.26(typescript@5.9.3)) + '@vueuse/integrations': 14.1.0(focus-trap@7.6.2)(jwt-decode@4.0.0)(vue@3.5.26(typescript@5.9.3)) focus-trap: 7.6.2 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) - vue-i18n@11.2.2(vue@3.5.25(typescript@5.9.3)): + vue-i18n@11.2.7(vue@3.5.26(typescript@5.9.3)): dependencies: - '@intlify/core-base': 11.2.2 - '@intlify/shared': 11.2.2 + '@intlify/core-base': 11.2.7 + '@intlify/shared': 11.2.7 '@vue/devtools-api': 6.6.4 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) vue-lazyload@3.0.0: {} - vue-reader@1.3.3: + vue-reader@1.3.4: dependencies: epubjs: 0.3.93 - vue-router@4.6.4(vue@3.5.25(typescript@5.9.3)): + vue-router@4.6.4(vue@3.5.26(typescript@5.9.3)): dependencies: '@vue/devtools-api': 6.6.4 - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) - vue-toastification@2.0.0-rc.5(vue@3.5.25(typescript@5.9.3)): + vue-toastification@2.0.0-rc.5(vue@3.5.26(typescript@5.9.3)): dependencies: - vue: 3.5.25(typescript@5.9.3) + vue: 3.5.26(typescript@5.9.3) - vue-tsc@3.1.8(typescript@5.9.3): + vue-tsc@3.2.0(typescript@5.9.3): dependencies: - '@volar/typescript': 2.4.26 - '@vue/language-core': 3.1.8(typescript@5.9.3) + '@volar/typescript': 2.4.27 + '@vue/language-core': 3.2.0 typescript: 5.9.3 - vue@3.5.25(typescript@5.9.3): + vue@3.5.26(typescript@5.9.3): dependencies: - '@vue/compiler-dom': 3.5.25 - '@vue/compiler-sfc': 3.5.25 - '@vue/runtime-dom': 3.5.25 - '@vue/server-renderer': 3.5.25(vue@3.5.25(typescript@5.9.3)) - '@vue/shared': 3.5.25 + '@vue/compiler-dom': 3.5.26 + '@vue/compiler-sfc': 3.5.26 + '@vue/runtime-dom': 3.5.26 + '@vue/server-renderer': 3.5.26(vue@3.5.26(typescript@5.9.3)) + '@vue/shared': 3.5.26 optionalDependencies: typescript: 5.9.3 diff --git a/filebrowser/frontend/src/i18n/hr.json b/filebrowser/frontend/src/i18n/hr.json index 79e1e045f3..7c2631981f 100644 --- a/filebrowser/frontend/src/i18n/hr.json +++ b/filebrowser/frontend/src/i18n/hr.json @@ -44,9 +44,9 @@ "openFile": "Otvori datoteku", "discardChanges": "Odbaci", "saveChanges": "Spremi promjene", - "editAsText": "Edit as Text", - "increaseFontSize": "Increase font size", - "decreaseFontSize": "Decrease font size" + "editAsText": "Uredi kao tekst", + "increaseFontSize": "Povećaj veličinu fonta", + "decreaseFontSize": "Smanji veličinu fonta" }, "download": { "downloadFile": "Preuzmi Datoteku", @@ -79,14 +79,14 @@ "sortByName": "Sortiraj po nazivu", "sortBySize": "Sortiraj po veličini", "noPreview": "Pregled nije dostupan za ovu datoteku.", - "csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.", - "csvLoadFailed": "Failed to load CSV file.", - "showingRows": "Showing {count} row(s)", - "columnSeparator": "Column Separator", + "csvTooLarge": "CSV datoteka je prevelika za pregled (>5MB). Molimo preuzmite da bi ste ju pregledali.", + "csvLoadFailed": "Neuspješno učitavanje CSV datoteke.", + "showingRows": "Prikazuje se {count} red(ova)", + "columnSeparator": "Separator stupaca", "csvSeparators": { - "comma": "Comma (,)", - "semicolon": "Semicolon (;)", - "both": "Both (,) and (;)" + "comma": "Zarez (,)", + "semicolon": "Točka zarez (;)", + "both": "I (,) i (;)" } }, "help": { diff --git a/filebrowser/frontend/src/i18n/ru.json b/filebrowser/frontend/src/i18n/ru.json index 5a92a2c760..50a8e2c74d 100644 --- a/filebrowser/frontend/src/i18n/ru.json +++ b/filebrowser/frontend/src/i18n/ru.json @@ -43,10 +43,10 @@ "upload": "Загрузить", "openFile": "Открыть файл", "discardChanges": "Отказаться", - "saveChanges": "Save changes", - "editAsText": "Edit as Text", - "increaseFontSize": "Increase font size", - "decreaseFontSize": "Decrease font size" + "saveChanges": "Сохранить", + "editAsText": "Редактировать как текст", + "increaseFontSize": "Увеличить размер шрифта", + "decreaseFontSize": "Уменьшить размер шрифта" }, "download": { "downloadFile": "Скачать файл", @@ -79,14 +79,14 @@ "sortByName": "Сортировка по имени", "sortBySize": "Сортировка по размеру", "noPreview": "Предварительный просмотр для этого файла недоступен.", - "csvTooLarge": "CSV file is too large for preview (>5MB). Please download to view.", - "csvLoadFailed": "Failed to load CSV file.", - "showingRows": "Showing {count} row(s)", - "columnSeparator": "Column Separator", + "csvTooLarge": "Этот CSV файл слишком большой для предпросмотра (>5 МБ). Скачайте и откройте его локально.", + "csvLoadFailed": "Не удалось загрузить этот CSV.", + "showingRows": "Отображается {count} строк(а)", + "columnSeparator": "Разделитель столбцов", "csvSeparators": { - "comma": "Comma (,)", - "semicolon": "Semicolon (;)", - "both": "Both (,) and (;)" + "comma": "Запятая (,)", + "semicolon": "Точка с запятой (;)", + "both": "Оба варианта — (,) и (;)" } }, "help": { @@ -114,9 +114,9 @@ "username": "Имя пользователя", "usernameTaken": "Данное имя пользователя уже занято", "wrongCredentials": "Неверные данные", - "passwordTooShort": "Password must be at least {min} characters", + "passwordTooShort": "Пароль должен состоять как минимум из {min} символов", "logout_reasons": { - "inactivity": "You have been logged out due to inactivity." + "inactivity": "Сессия завершена после долгого отсутствия." } }, "permanent": "Постоянный", @@ -171,7 +171,7 @@ "video": "Видео" }, "settings": { - "aceEditorTheme": "Ace editor theme", + "aceEditorTheme": "Тема редактора Ace", "admin": "Админ", "administrator": "Администратор", "allowCommands": "Запуск команд", @@ -179,7 +179,7 @@ "allowNew": "Создание новых файлов или каталогов", "allowPublish": "Публикация новых записей и страниц", "allowSignup": "Разрешить пользователям регистрироваться", - "hideLoginButton": "Hide the login button from public pages", + "hideLoginButton": "Спрятать кнопку входа с публичных страниц", "avoidChanges": "(оставьте поле пустым, чтобы избежать изменений)", "branding": "Брендинг", "brandingDirectoryPath": "Путь к каталогу брендов", @@ -189,7 +189,7 @@ "commandRunnerHelp": "Здесь вы можете установить команды, которые будут выполняться в указанных событиях. Вы должны указать по одной команде в каждой строке. Переменные среды {0} и {1} будут доступны, будучи {0} относительно {1}. Дополнительные сведения об этой функции и доступных переменных среды см. В {2}.", "commandsUpdated": "Команды обновлены!", "createUserDir": "Автоматическое создание домашнего каталога пользователя при добавлении нового пользователя", - "minimumPasswordLength": "Minimum password length", + "minimumPasswordLength": "Минимальная длина пароля", "tusUploads": "Загруженные файлы", "tusUploadsHelp": " File Browser поддерживает загрузку файлов по частям, что позволяет работать в сетях низкого качества.", "tusUploadsChunkSize": "Указывает максимальный размер запроса (мелкие загрузки пойдут напрямую). Вы можете ввести простое целое число, обозначающее размер ввода в байтах, или строку, например 10MB, 1GB и т. д.", diff --git a/filebrowser/go.mod b/filebrowser/go.mod index 39bdf22c7a..1052747adf 100644 --- a/filebrowser/go.mod +++ b/filebrowser/go.mod @@ -12,7 +12,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/gorilla/websocket v1.5.3 github.com/jellydator/ttlcache/v3 v3.4.0 - github.com/maruel/natural v1.2.1 + github.com/maruel/natural v1.3.0 github.com/marusama/semaphore/v2 v2.5.0 github.com/mholt/archives v0.1.5 github.com/mitchellh/go-homedir v1.1.0 diff --git a/filebrowser/go.sum b/filebrowser/go.sum index e239fb199c..7d30527435 100644 --- a/filebrowser/go.sum +++ b/filebrowser/go.sum @@ -169,8 +169,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/maruel/natural v1.2.1 h1:G/y4pwtTA07lbQsMefvsmEO0VN0NfqpxprxXDM4R/4o= -github.com/maruel/natural v1.2.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= +github.com/maruel/natural v1.3.0 h1:VsmCsBmEyrR46RomtgHs5hbKADGRVtliHTyCOLFBpsg= +github.com/maruel/natural v1.3.0/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM= github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ= github.com/mholt/archives v0.1.5 h1:Fh2hl1j7VEhc6DZs2DLMgiBNChUux154a1G+2esNvzQ= diff --git a/geoip/config.json b/geoip/config.json index 8f4e806a1d..d765406447 100644 --- a/geoip/config.json +++ b/geoip/config.json @@ -346,10 +346,7 @@ }, { "type": "surgeRuleSet", - "action": "output", - "args": { - "addSuffixInLine": ",no-resolve" - } + "action": "output" } ] } diff --git a/mihomo/transport/gun/gun.go b/mihomo/transport/gun/gun.go index 35639c12be..3ac548ddfc 100644 --- a/mihomo/transport/gun/gun.go +++ b/mihomo/transport/gun/gun.go @@ -12,6 +12,7 @@ import ( "io" "net" "net/url" + "strings" "sync" "time" @@ -331,11 +332,19 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, clientFingerprint stri return wrap } +func ServiceNameToPath(serviceName string) string { + if strings.HasPrefix(serviceName, "/") { // custom paths + return serviceName + } + return "/" + serviceName + "/Tun" +} + func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, error) { serviceName := "GunService" if cfg.ServiceName != "" { serviceName = cfg.ServiceName } + path := ServiceNameToPath(serviceName) reader, writer := io.Pipe() request := &http.Request{ @@ -344,9 +353,9 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er URL: &url.URL{ Scheme: "https", Host: cfg.Host, - Path: fmt.Sprintf("/%s/Tun", serviceName), + Path: path, // for unescape path - Opaque: fmt.Sprintf("//%s/%s/Tun", cfg.Host, serviceName), + Opaque: "//" + cfg.Host + path, }, Proto: "HTTP/2", ProtoMajor: 2, diff --git a/mihomo/transport/gun/server.go b/mihomo/transport/gun/server.go index 16605b4342..c240459fee 100644 --- a/mihomo/transport/gun/server.go +++ b/mihomo/transport/gun/server.go @@ -24,7 +24,7 @@ type ServerOption struct { } func NewServerHandler(options ServerOption) http.Handler { - path := "/" + options.ServiceName + "/Tun" + path := ServiceNameToPath(options.ServiceName) connHandler := options.ConnHandler httpHandler := options.HttpHandler if httpHandler == nil { diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/Makefile b/openwrt-packages/luci-app-partexp/luci-app-partexp/Makefile index c9e4e73bdf..1d5ada132a 100644 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/Makefile +++ b/openwrt-packages/luci-app-partexp/luci-app-partexp/Makefile @@ -7,15 +7,15 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-partexp -PKG_VERSION:=1.3.2 -PKG_RELEASE:=20250706 +LUCI_TITLE:=LuCI Support for Automatic Partition Mount +LUCI_PKGARCH:=all +LUCI_DEPENDS:=+fdisk +block-mount +bc +blkid +parted +btrfs-progs +losetup +resize2fs +e2fsprogs +f2fs-tools +kmod-loop +PKG_VERSION:=2.0.2 +PKG_RELEASE:=20251221 PKG_LICENSE:=Apache-2.0 PKG_MAINTAINER:=Sirpdboy -LUCI_TITLE:=LuCI Support for Automatic Partition Mount -LUCI_DEPENDS:=+fdisk +block-mount +bc +blkid +parted +btrfs-progs +losetup +resize2fs +e2fsprogs +f2fs-tools +kmod-loop -LUCI_PKGARCH:=all include $(TOPDIR)/feeds/luci/luci.mk diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/README.md b/openwrt-packages/luci-app-partexp/luci-app-partexp/README.md deleted file mode 100644 index 35356edcf9..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/README.md +++ /dev/null @@ -1,127 +0,0 @@ -### 访问数:[![](https://visitor-badge.glitch.me/badge?page_id=sirpdboy-visitor-badge)] [![](https://img.shields.io/badge/TG群-点击加入-FFFFFF.svg)](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ) - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明1.jpg) - -= -# luci-app-partexp - -luci-app-partexp 一键自动格式化分区、扩容、自动挂载插件 -[![若部分图片无法正常显示,请挂上机场浏览或点这里到末尾看修复教程](https://visitor-badge.glitch.me/badge?page_id=sirpdboy-visitor-badge)](#解决-github-网页上图片显示失败的问题) [![](https://img.shields.io/badge/TG群-点击加入-FFFFFF.svg)](https://t.me/joinchat/AAAAAEpRF88NfOK5vBXGBQ) - -[luci-app-partexp](https://github.com/sirpdboy/luci-app-partexp) -====================== - - -请 **认真阅读完毕** 本页面,本页面包含注意事项和如何使用。 - -## 功能说明: - - -#### 一键自动格式化分区、扩容、自动挂载插件,专为OPENWRT设计,简化OPENWRT在分区挂载上烦锁的操作。本插件是sirpdboy耗费大量精力制作测试,请勿删除制作者信息!! - - - -- [partexp](#luci-app-partexp) - - [特性](#特性) - - [使用方法](#使用方法) - - [说明](#说明) - - [界面](#界面) - - [捐助](#捐助) - - - -## 版本 - -- 最新更新版本号: V1.3.1 -- 更新日期:2025年3月26日 -- 更新内容: -- 重新整理分区扩容代码,解决一些不合理的地方。 -- 加入对目标分区的格式,可以指定格式化为ext4,ntfs和Btrfs以及不格式化。 -- 当做为根目录 /或者 /overlay时,密然会格式化为ext4格式。 -- 目前在X86的机器上测试完全正常,其它路由设备上未测试。有问题请提交硬盘分区情况和错误提示。 - - -## 特性 - luci-app-partexp 自动获格式化分区扩容,自动挂载插件 - -## 使用方法 - -- 将luci-app-partexp添加至 LEDE/OpenWRT 源码的方法。 - -### 下载源码方法: - - ```Brach - - # 下载源码 - - git clone https://github.com/sirpdboy/luci-app-partexp.git package/luci-app-partexp - make menuconfig - - ``` -### 配置菜单 - - ```Brach - make menuconfig - # 找到 LuCI -> Applications, 选择 luci-app-partexp, 保存后退出。 - ``` - -### 编译 - - ```Brach - # 编译固件 - make package/luci-app-partexp/compile V=s - ``` - -## 说明 - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明2.jpg) - -## 界面 - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/partexp.png) - - - - -## 使用与授权相关说明 - -- 本人开源的所有源码,任何引用需注明本处出处,如需修改二次发布必告之本人,未经许可不得做于任何商用用途。 - - -# My other project - -- 网络速度测试 :https://github.com/sirpdboy/NetSpeedTest - -- 定时设置插件 : https://github.com/sirpdboy/luci-app-autotimeset - -- 关机功能插件 : https://github.com/sirpdboy/luci-app-poweroffdevice - -- opentopd主题 : https://github.com/sirpdboy/luci-theme-opentopd - -- kucat 主题: https://github.com/sirpdboy/luci-theme-kucat - -- 家长控制: https://github.com/sirpdboy/luci-theme-parentcontrol - -- 系统高级设置 : https://github.com/sirpdboy/luci-app-advanced - -- ddns-go动态域名: https://github.com/sirpdboy/luci-app-ddns-go - -- 进阶设置(系统高级设置+主题设置kucat/agron/opentopd): https://github.com/sirpdboy/luci-app-advancedplus - -- 设置向导: https://github.com/sirpdboy/luci-app-wizard - -- 分区扩容: https://github.com/sirpdboy/luci-app-partexp - -- lukcy大吉: https://github.com/sirpdboy/luci-app-lukcy - -## 捐助 - -![screenshots](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/说明3.jpg) - -| 图飞了😂 | 图飞了😂 | -| :-----------------: | :-------------: | -|![xm1](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/支付宝.png) | ![xm1](https://raw.githubusercontent.com/sirpdboy/openwrt/master/doc/微信.png) | - - - 图飞了😂 - diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/htdocs/luci-static/resources/view/partexp.js b/openwrt-packages/luci-app-partexp/luci-app-partexp/htdocs/luci-static/resources/view/partexp.js new file mode 100644 index 0000000000..79e5211045 --- /dev/null +++ b/openwrt-packages/luci-app-partexp/luci-app-partexp/htdocs/luci-static/resources/view/partexp.js @@ -0,0 +1,963 @@ +/* + * Copyright (C) 2022-2025 Sirpdboy + * + * Licensed to the public under the Apache License 2.0 + */ + +'use strict'; + +'require form'; +'require fs'; +'require rpc'; +'require uci'; +'require ui'; +'require view'; + +// 声明 RPC 接口 +var callPartExpAutopart = rpc.declare({ + object: 'partexp', + method: 'autopart' +}); + +var callPartExpGetLog = rpc.declare({ + object: 'partexp', + method: 'get_log', + params: ['position'] +}); + +var callPartExpGetDevices = rpc.declare({ + object: 'partexp', + method: 'get_devices' +}); + +var callPartExpGetStatus = rpc.declare({ + object: 'partexp', + method: 'get_status' +}); + +// 添加保存配置的 RPC 声明 +var callPartExpSaveConfig = rpc.declare({ + object: 'partexp', + method: 'save_config', + params: ['target_function', 'target_disk', 'keep_config', 'format_type'] +}); + +return view.extend({ + load: function() { + return Promise.all([ + L.resolveDefault(fs.stat('/usr/bin/partexp'), null), + L.resolveDefault(fs.stat('/tmp/partexp.log'), null) + ]); + }, + + render: function(data) { + var container = E('div', { class: 'cbi-map' }); + var htmlParts = [ + '', + '

' + _('One click partition expansion mounting tool') + '

', + '
', + '
', + ' ' + _('Automatically format and mount the target device partition. If there are multiple partitions, it is recommended to manually delete all partitions before using this tool.') + '
', + ' ' + _('For specific usage, see:') + ' ', + ' ', + ' GitHub @partexp', + ' ', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + ' ', + '
', + ' ', + '
' + _('Select the function to be performed') + '
', + '
', + '
', + '
', + ' ', + '
', + ' ', + '
' + _('Select the hard disk device to operate') + '
', + '
', + '
', + '
', + ' ', + '
', + ' ', + ' ', + '
', + '
', + '
', + ' ', + '
', + ' ', + '
', + '
', + '
', + ' ', + '
', + ' ', + '
', + '
', + '
', + '
', + '
', + '
', + ' ', + '
', + '
', + '
', + '
0%
', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + ' ', + '
', + ' ', + '
', + '
', + '
', + '
' + ]; + container.innerHTML = htmlParts.join(''); + + var self = this; + + // uci 对象已经在全局作用域可用 + var uci = self.uci || window.uci; + setTimeout(function() { + self.initDOM(); + self.bindEvents(); + self.loadDevices(); + self.loadSavedConfig(); + self.checkOperationStatus(); + self.loadExistingLog(); + }, 100); + + return container; + }, + + initDOM: function() { + this.dom = { + stateContainer: document.querySelector('#state-container'), + targetFunction: document.querySelector('#target_function'), + targetDisk: document.querySelector('#target_disk'), + keepConfig: document.querySelector('#keep_config'), + formatType: document.querySelector('#format_type'), + executeBtn: document.querySelector('#execute-btn'), + logView: document.querySelector('#log-view'), + progressBar: document.querySelector('#progress-bar'), + progressText: document.querySelector('#progress-text'), + executeStatus: document.querySelector('#execute_status') + }; + + // 初始化状态变量 + this.logPosition = '0'; + this.logPolling = null; + this.isRunning = false; + this.operationComplete = false; + this.pollErrorCount = 0; + this.pollingStartTime = 0; + this.lastPollTime = 0; + this.currentProgress = 0; + this.autoSaveTimer = null; + this.isNewOperation = false; // 标记是否是新操作 + }, + + bindEvents: function() { + var self = this; + if (this.dom.executeBtn) { + this.dom.executeBtn.addEventListener('click', function(e) { + e.preventDefault(); + self.executeOperation(); + }); + } + + // 表单变化事件 - 自动保存 + [this.dom.targetFunction, this.dom.targetDisk, this.dom.formatType].forEach(function(element) { + if (element) { + element.addEventListener('change', function() { + self.autoSaveConfig(); + self.updateFormVisibility(); + }); + } + }); + + // 复选框特殊处理 + if (this.dom.keepConfig) { + this.dom.keepConfig.addEventListener('click', function() { + self.autoSaveConfig(); + }); + } + + // 初始化表单可见性 + if (this.dom.targetFunction) { + this.updateFormVisibility(); + } + }, + + // 加载设备列表 + loadDevices: function() { + var self = this; + + callPartExpGetDevices().then(function(response) { + if (!response || !response.devices || response.devices.length === 0) { + return; + } + + // 清空设备列表 + if (self.dom.targetDisk) { + self.dom.targetDisk.innerHTML = ''; + + // 添加设备选项 + response.devices.forEach(function(device) { + var option = document.createElement('option'); + option.value = device.name; + option.textContent = device.name + ' (' + device.dev + ', ' + device.size + ' MB)'; + self.dom.targetDisk.appendChild(option); + }); + } + }).catch(function(error) { + console.error('Failed to load devices:', error); + }); + }, + + // 加载现有的日志文件内容 + loadExistingLog: function() { + var self = this; + + // 初始化时获取现有日志内容 + callPartExpGetLog('0').then(function(response) { + if (response && response.log) { + var logContent = response.log.toString().trim(); + if (logContent && self.dom.logView) { + // 显示现有日志内容 + self.dom.logView.value = logContent; + + // 自动滚动到底部 + setTimeout(function() { + if (self.dom.logView && self.dom.logView.value) { + self.dom.logView.scrollTop = self.dom.logView.scrollHeight; + } + }, 100); + + // 更新日志位置 + if (response.position) { + self.logPosition = response.position; + } + if (!self.isRunning && logContent.includes('正在执行') && !logContent.includes('操作完成')) { + self.isRunning = true; + self.switchState('executing'); + self.startLogPolling(); + } + } + } + }).catch(function(error) { + console.error('Failed to load existing log:', error); + }); + }, + + loadSavedConfig: function() { + var self = this; + + return fs.read('/etc/config/partexp').then(function(content) { + if (!content) { + self.setDefaultConfig(); + return; + } + + // 解析配置文件 + var lines = content.split('\n'); + var config = {}; + + lines.forEach(function(line) { + line = line.trim(); + if (line.startsWith('option')) { + var parts = line.split(/\s+/); + if (parts.length >= 3) { + var key = parts[1]; + var value = parts.slice(2).join(' ').replace(/^['"]|['"]$/g, ''); + config[key] = value; + } + } + }); + + // 设置表单值 + if (self.dom.targetFunction) { + self.dom.targetFunction.value = config.target_function || '/opt'; + } + if (self.dom.targetDisk && config.target_disk) { + // 等待设备加载完成后设置 + setTimeout(function() { + if (self.dom.targetDisk) { + self.dom.targetDisk.value = config.target_disk; + } + }, 500); + } + if (self.dom.keepConfig) { + self.dom.keepConfig.checked = (config.keep_config === '1'); + } + if (self.dom.formatType) { + self.dom.formatType.value = config.format_type || '0'; + } + + // 更新配置缓存 + self.configCache = config; + + // 更新表单可见性 + self.updateFormVisibility(); + + }).catch(function(error) { + console.log('Failed to load config:', error); + self.setDefaultConfig(); + }); + }, + + // 设置默认配置 + setDefaultConfig: function() { + if (this.dom.targetFunction) { + this.dom.targetFunction.value = '/opt'; + } + if (this.dom.formatType) { + this.dom.formatType.value = '0'; + } + if (this.dom.keepConfig) { + this.dom.keepConfig.checked = false; + } + this.updateFormVisibility(); + + this.configCache = { + target_function: '/opt', + target_disk: '', + keep_config: '0', + format_type: '0' + }; + }, + + // 自动保存配置(防抖处理) + autoSaveConfig: function() { + var self = this; + + // 清除之前的定时器 + if (this.autoSaveTimer) { + clearTimeout(this.autoSaveTimer); + } + + // 设置新的定时器,1.5秒后保存 + this.autoSaveTimer = setTimeout(function() { + self.saveCurrentConfig(); + }, 1500); + }, + + // 保存当前配置 + saveCurrentConfig: function() { + var self = this; + + // 获取当前表单值 + var targetFunction = this.dom.targetFunction ? this.dom.targetFunction.value : '/opt'; + var targetDisk = this.dom.targetDisk ? this.dom.targetDisk.value : ''; + var keepConfig = this.dom.keepConfig ? this.dom.keepConfig.checked : false; + var formatType = this.dom.formatType ? this.dom.formatType.value : '0'; + if (callPartExpSaveConfig) { + return callPartExpSaveConfig( + targetFunction, + targetDisk, + keepConfig ? '1' : '0', + formatType + ).then(function(response) { + if (response && response.success) { + + self.configCache = { + target_function: targetFunction, + target_disk: targetDisk, + keep_config: keepConfig ? '1' : '0', + format_type: formatType + }; + + return true; + } else { + console.warn('RPC save failed, falling back to file write'); + return self.saveConfigToFile(targetFunction, targetDisk, keepConfig, formatType); + } + }).catch(function(error) { + console.error('RPC save config error:', error); + return self.saveConfigToFile(targetFunction, targetDisk, keepConfig, formatType); + }); + } else { + // 如果 RPC 不可用,直接使用文件写入 + return self.saveConfigToFile(targetFunction, targetDisk, keepConfig, formatType); + } + }, + + // 备选方案:直接写入配置文件 + saveConfigToFile: function(targetFunction, targetDisk, keepConfig, formatType) { + var configContent = [ + '# Auto-generated by partexp', + '', + 'config global global', + "\toption target_function '" + targetFunction + "'", + "\toption target_disk '" + targetDisk + "'", + "\toption keep_config '" + (keepConfig ? '1' : '0') + "'", + "\toption format_type '" + formatType + "'", + '' + ].join('\n'); + + return fs.write('/etc/config/partexp', configContent).then(function() { + console.log('Settings saved to file /etc/config/partexp'); + return true; + }).catch(function(error) { + console.error('Failed to save settings to file:', error); + return false; + }); + }, + + // 执行操作 + executeOperation: function() { + var self = this; + + // 先保存配置 + this.saveCurrentConfig(); + var target_function = this.dom.targetFunction.value; + var target_disk = this.dom.targetDisk.value; + + if (target_function !== '/' && (!target_disk || target_disk.trim() === '')) { + alert(_('Please select a target disk')); + return; + } + + // 确认操作 + var confirmMessage = _('Are you sure you want to execute partition expansion?') + '\n\n' + + _('Function:') + ' ' + this.getFunctionDescription(target_function) + '\n' + + (target_function !== '/' ? _('Disk:') + ' ' + target_disk + '\n' : '') + + (target_function === '/' || target_function === '/overlay' ? + _('Keep config:') + ' ' + (this.dom.keepConfig.checked ? _('Yes') : _('No')) + '\n' : '') + + (target_function === '/opt' || target_function === '/dev' ? + _('Format type:') + ' ' + this.getFormatTypeDescription(this.dom.formatType.value) + '\n' : '') + + '\n' + _('This operation may take several minutes.'); + + if (!confirm(confirmMessage)) { + return; + } + + // 重置操作状态 + this.resetOperationState(); + + // 标记为新操作开始 + this.isNewOperation = true; + + if (this.dom.logView) { + this.dom.logView.value = _('正在启动操作...'); + } + + // 更新按钮状态 + if (this.dom.executeBtn) { + this.dom.executeBtn.disabled = true; + this.dom.executeBtn.textContent = _('Executing...'); + } + + // 切换到执行状态 + this.switchState('executing'); + + // 开始进度显示 + this.updateProgress(5, _('Starting operation...')); + + // 调用分区操作 + callPartExpAutopart() + .then(function(response) { + if (response && response.success) { + // 操作开始成功 + self.isRunning = true; + self.operationComplete = false; + self.startLogPolling(); + + if (self.dom.executeStatus) { + self.dom.executeStatus.textContent = _('Operation started successfully'); + } + } else { + // 操作启动失败 + var errorMsg = response && response.message ? response.message : _('Operation failed'); + self.handleOperationError(errorMsg); + } + }) + .catch(function(error) { + console.error('Operation failed:', error); + self.handleOperationError(_('Failed to start operation:') + ' ' + (error.message || _('Unknown error'))); + }); + }, + + // 重置操作状态 + resetOperationState: function() { + this.logPosition = '0'; + this.isRunning = true; + this.operationComplete = false; + this.pollErrorCount = 0; + this.pollingStartTime = Date.now(); + this.lastPollTime = 0; + this.currentProgress = 0; + + // 重置进度条 + this.updateProgress(0, _('Starting operation...')); + }, + + // 处理操作错误 + handleOperationError: function(errorMsg) { + alert(errorMsg); + if (this.dom.executeBtn) { + this.dom.executeBtn.disabled = false; + this.dom.executeBtn.textContent = _('Click to execute'); + } + + this.switchState('ready'); + this.stopLogPolling(); + + // 在日志中显示错误信息 + if (this.dom.logView) { + var currentLog = this.dom.logView.value || ''; + this.dom.logView.value = currentLog + '\n\n' + _('操作失败:') + ' ' + errorMsg; + setTimeout(() => { + if (this.dom.logView) { + this.dom.logView.scrollTop = this.dom.logView.scrollHeight; + } + }, 100); + } + }, + + // 更新表单可见性 + updateFormVisibility: function() { + if (!this.dom.targetFunction || !this.dom.targetDisk || + !this.dom.keepConfig || !this.dom.formatType) return; + + var func = this.dom.targetFunction.value; + var diskDiv = this.dom.targetDisk.closest('.cbi-value'); + var keepDiv = this.dom.keepConfig.closest('.cbi-value'); + var formatDiv = this.dom.formatType.closest('.cbi-value'); + + if (!diskDiv || !keepDiv || !formatDiv) return; + + if (func === '/') { + diskDiv.style.display = 'none'; + formatDiv.style.display = 'none'; + keepDiv.style.display = 'block'; + } else if (func === '/overlay') { + diskDiv.style.display = 'block'; + formatDiv.style.display = 'none'; + keepDiv.style.display = 'block'; + } else { + diskDiv.style.display = 'block'; + formatDiv.style.display = 'block'; + keepDiv.style.display = 'none'; + } + }, + + // 检查操作状态 + checkOperationStatus: function() { + var self = this; + + callPartExpGetStatus().then(function(response) { + if (response && response.running) { + // 有操作在进行中 + self.isRunning = true; + self.switchState('executing'); + self.startLogPolling(); + + // 禁用执行按钮 + if (self.dom.executeBtn) { + self.dom.executeBtn.disabled = true; + self.dom.executeBtn.textContent = _('Operation in progress...'); + } + + // 更新状态 + if (self.dom.executeStatus) { + self.dom.executeStatus.textContent = _('Operation in progress...'); + } + } + }).catch(function(error) { + console.error('Failed to check operation status:', error); + }); + }, + + // 开始轮询日志 + startLogPolling: function() { + var self = this; + + // 停止现有的轮询 + this.stopLogPolling(); + + // 重置状态 + this.pollErrorCount = 0; + this.pollingStartTime = Date.now(); + this.lastPollTime = 0; + + // 更新进度显示 + this.updateProgress(10, _('Operation in progress...')); + + // 开始轮询 + this.logPolling = setInterval(function() { + // 检查是否超时(20分钟超时) + if (Date.now() - self.pollingStartTime > 20 * 60 * 1000) { + console.error('Operation timeout'); + self.stopLogPolling(); + self.isRunning = false; + + // 显示超时信息 + if (self.dom.logView) { + var currentLog = self.dom.logView.value || ''; + self.dom.logView.value = currentLog + '\n\n[超时] 操作超过20分钟未完成,请检查系统'; + setTimeout(() => { + if (self.dom.logView) { + self.dom.logView.scrollTop = self.dom.logView.scrollHeight; + } + }, 100); + } + + self.switchState('ready'); + + if (self.dom.executeBtn) { + self.dom.executeBtn.disabled = false; + self.dom.executeBtn.textContent = _('Click to execute'); + } + return; + } + + self.pollLog(); + }, 3000); // 每3秒轮询一次,减少频率 + }, + + pollLog: function() { + var self = this; + + if (!this.isRunning) { + this.stopLogPolling(); + return; + } + + var pollStartTime = Date.now(); + + // 总是从位置0开始获取完整日志内容 + callPartExpGetLog('0').then(function(response) { + if (!response) { + console.error('No response from log polling'); + return; + } + + if (pollStartTime < self.lastPollTime) { + return; + } + + self.lastPollTime = pollStartTime; + + // 处理日志内容 + if (response.log !== undefined) { + var logContent = response.log.toString().trim(); + + if (response.position) { + self.logPosition = response.position; + } + + if (self.dom.logView) { + if (logContent !== '') { + self.dom.logView.value = logContent; + + // 自动滚动到底部 + setTimeout(function() { + if (self.dom.logView && self.dom.logView.value) { + self.dom.logView.scrollTop = self.dom.logView.scrollHeight; + } + }, 50); + } + } + + // 更新进度 + self.parseAndUpdateProgress(logContent); + + // 检查操作是否完成 + if (self.checkOperationComplete(logContent)) { + self.handleOperationComplete(); + } + } + + // 检查RPC返回的完成状态 + if (response.complete) { + self.handleOperationComplete(); + } + + // 重置错误计数 + self.pollErrorCount = 0; + + }).catch(function(error) { + console.error('Log polling error:', error); + + // 如果多次失败,停止轮询 + self.pollErrorCount = (self.pollErrorCount || 0) + 1; + if (self.pollErrorCount > 5) { + console.error('Too many polling errors, stopping'); + self.stopLogPolling(); + self.isRunning = false; + self.switchState('ready'); + + if (self.dom.executeBtn) { + self.dom.executeBtn.disabled = false; + self.dom.executeBtn.textContent = _('Click to execute'); + } + // 显示错误信息 + if (self.dom.logView) { + var currentLog = self.dom.logView.value || ''; + self.dom.logView.value = currentLog + '\n\n[错误] 日志轮询失败,请刷新页面查看最新状态'; + setTimeout(() => { + if (self.dom.logView) { + self.dom.logView.scrollTop = self.dom.logView.scrollHeight; + } + }, 100); + } + } + }); + }, + + // 检查操作是否完成 + checkOperationComplete: function(logText) { + if (!logText) return false; + + // 检查日志中是否包含操作完成标记 + var completeMarkers = [ + '重启设备', + '操作完成' + ]; + + for (var i = 0; i < completeMarkers.length; i++) { + if (logText.includes(completeMarkers[i])) { + return true; + } + } + + return false; + }, + + // 处理操作完成 + handleOperationComplete: function() { + if (this.operationComplete) { + return; + } + + this.operationComplete = true; + this.isRunning = false; + this.isNewOperation = false; + + // 立即停止轮询 + this.stopLogPolling(); + if (this.dom.logView) { + var currentLog = this.dom.logView.value || ''; + if (!currentLog.includes('操作完成')) { + this.dom.logView.value = currentLog; + setTimeout(() => { + if (this.dom.logView) { + this.dom.logView.scrollTop = this.dom.logView.scrollHeight; + } + }, 100); + } + } + + // 进度条显示100% + this.updateProgress(100, _('Operation completed')); + + // 启用执行按钮 + setTimeout(() => { + if (this.dom.executeBtn) { + this.dom.executeBtn.disabled = false; + this.dom.executeBtn.textContent = _('Click to execute'); + } + + // 切换回就绪状态 + setTimeout(() => { + this.switchState('ready'); + }, 3000); + }, 2000); + }, + + // 解析并更新进度 + parseAndUpdateProgress: function(logText) { + if (!logText || !this.dom.executeStatus) return; + + // 尝试从日志中提取进度信息 + var percent = 0; + var statusMessage = _('Operation in progress...'); + + if (logText.includes('100%') || logText.includes('操作完成') || logText.includes('扩容成功')) { + percent = 100; + statusMessage = _('Operation completed'); + } else if ( logText.includes('错误') || logText.includes('error')) { + // 错误情况,不更新进度 + return; + } else if (logText.includes('分区扩容和挂载到') || logText.includes('正在挂载')) { + percent = 90; + statusMessage = _('Getting device information'); + } else if (logText.includes('检测设备')) { + percent = 60; + statusMessage = _('Checking partition format'); + } else if (logText.includes('开始检测目标')) { + percent = 50; + statusMessage = _('Checking target device'); + } else if (logText.includes('定位到操作目标设备分区')) { + percent = 40; + statusMessage = _('Locating target partition'); + } else if (logText.includes('目标盘') && logText.includes('有剩余空间')) { + percent = 30; + statusMessage = _('Checking free space'); + } else if (logText.includes('操作功能')) { + percent = 20; + statusMessage = _('Starting operation'); + } else if (logText.includes('开始执行') || logText.includes('Starting')) { + percent = 10; + statusMessage = _('Initializing...'); + } + + // 确保进度不会倒退 + if (percent > 0) { + this.currentProgress = Math.max(this.currentProgress || 0, percent); + } else { + // 如果没有明确的进度标记,逐渐增加进度 + this.currentProgress = Math.min(90, (this.currentProgress || 0) + 1); + } + + // 更新进度显示 + this.updateProgress(this.currentProgress, statusMessage); + }, + + // 更新进度显示 + updateProgress: function(percent, message) { + if (!this.dom.progressBar || !this.dom.progressText || !this.dom.executeStatus) { + return; + } + + // 确保百分比在有效范围内 + percent = Math.max(0, Math.min(100, percent)); + + // 更新进度条 + this.dom.progressBar.style.width = percent + '%'; + + // 更新进度文本 + this.dom.progressText.textContent = percent + '%'; + + // 更新状态消息 + this.dom.executeStatus.textContent = message; + }, + + // 停止轮询日志 + stopLogPolling: function() { + if (this.logPolling) { + clearInterval(this.logPolling); + this.logPolling = null; + } + }, + + // 切换状态 + switchState: function(to) { + if (!this.dom.stateContainer) return; + + // 移除所有状态类 + this.dom.stateContainer.classList.remove( + 'state-ctl-ready', + 'state-ctl-executing' + ); + + // 添加新状态类 + this.dom.stateContainer.classList.add('state-ctl-' + to); + }, + + // 获取功能描述 + getFunctionDescription: function(func) { + switch(func) { + case '/': return _('Extend to root directory'); + case '/overlay': return _('Expand overlay'); + case '/opt': return _('Docker data disk'); + case '/dev': return _('Normal mount'); + default: return func; + } + }, + + // 获取格式化类型描述 + getFormatTypeDescription: function(type) { + switch(type) { + case '0': return _('No formatting'); + case 'ext4': return _('EXT4'); + case 'btrfs': return _('Btrfs'); + case 'ntfs': return _('NTFS'); + default: return type; + } + }, + + // 页面生命周期方法 + handleSaveApply: null, + handleSave: null, + handleReset: null +}); \ No newline at end of file diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/controller/partexp.lua b/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/controller/partexp.lua deleted file mode 100644 index 7fb671da9f..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/controller/partexp.lua +++ /dev/null @@ -1,50 +0,0 @@ ---[[ -LuCI - Lua Configuration Partition Expansion - Copyright (C) 2022-2025 sirpdboy https://github.com/sirpdboy/partexp -]]-- - -local fs = require "nixio.fs" -local http = require "luci.http" -local uci = require"luci.model.uci".cursor() -local name = 'partexp' - -module("luci.controller.partexp", package.seeall) - -function index() - local e = entry({"admin","system","partexp"},alias("admin", "system", "partexp", "global"),_("Partition Expansion"), 54) - e.dependent = false - e.acl_depends = { "luci-app-partexp" } - entry({"admin","system","partexp","global"}, cbi('partexp/global', {hideapplybtn = true, hidesavebtn = true, hideresetbtn = true}), _('Partition Expansion'), 10).leaf = true - entry({"admin", "system", "partexp","partexprun"}, call("partexprun")) - entry({"admin", "system", "partexp", "check"}, call("act_check")) -end -function act_check() - - http.prepare_content("text/plain; charset=utf-8") - local f=io.open("/tmp/partexp.log", "r+") - local fdp=fs.readfile("/tmp/lucilogpos") or 0 - f:seek("set",fdp) - local a=f:read(2048000) or "" - fdp=f:seek() - fs.writefile("/tmp/lucilogpos",tostring(fdp)) - f:close() - http.write(a) -end - - - -function partexprun() - local kconfig = http.formvalue('kconfig') - local eformat = http.formvalue('eformat') - local targetf = http.formvalue('targetf') - local targetd = http.formvalue('targetd') - uci:set(name, 'global', 'target_disk', targetd) - uci:set(name, 'global', 'target_function', targetf) - uci:set(name, 'global', 'format_type', eformat) - uci:set(name, 'global', 'keep_config', kconfig) - uci:commit(name) - fs.writefile("/tmp/lucilogpos","0") - http.prepare_content("application/json") - http.write('') - luci.sys.exec("/etc/init.d/partexp autopart > /tmp/partexp.log 2>&1 &") -end diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/model/cbi/partexp/global.lua b/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/model/cbi/partexp/global.lua deleted file mode 100644 index 5d985cb1a3..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/model/cbi/partexp/global.lua +++ /dev/null @@ -1,79 +0,0 @@ ---[[ -LuCI - Lua Configuration Interface - Copyright (C) 2022-2025 sirpdboy https://github.com/sirpdboy/luci-app-partexp -]]-- -local fs = require "nixio.fs" -local util = require "nixio.util" -local tp = require "luci.template.parser" -local uci=luci.model.uci.cursor() -luci.sys.exec("echo '-' >/tmp/partexp.log&&echo 1 > /tmp/lucilogpos" ) -local target_devnames = {} -for dev in fs.dir("/dev") do - if dev:match("^sd[a-z]$") - or dev:match("^mmcblk%d+$") - or dev:match("^sata[a-z]$") - or dev:match("^nvme%d+n%d+$") - or dev:match("^vd[a-z]") - then - table.insert(target_devnames, dev) - end -end - local devices = {} - for i, bname in pairs(target_devnames) do - local device_info = {} - local device = "/dev/" .. bname - device_info["name"] = bname - device_info["dev"] = device - - s = tonumber((fs.readfile("/sys/class/block/%s/size" % bname))) - device_info["size"] = s and math.floor(s / 2048) - - devices[#devices+1] = device_info -end - -local m,t,e -m = Map("partexp", "" .. translate("One click partition expansion mounting tool") .."", -translate( "Automatically format and mount the target device partition. If there are multiple partitions, it is recommended to manually delete all partitions before using this tool.
For specific usage, see:") ..translate("GitHub @sirpdboy:luci-app-partexp") ) - -t=m:section(TypedSection,"global") -t.anonymous=true - -e=t:option(ListValue,"target_function", translate("Select function"),translate("Select the function to be performed")) -e:value("/", translate("Used to extend to the root directory of EXT4 firmware(Ext4 /)")) -e:value("/overlay", translate("Expand application space overlay (/overlay)")) -e:value("/opt", translate("Used as Docker data disk (/opt)")) -e:value("/dev", translate("Normal mount and use by device name(/mnt/x1)")) -e.default="/opt" - -e=t:option(ListValue,"target_disk", translate("Destination hard disk"),translate("Select the hard disk device to operate")) -e:depends("target_function", "/overlay") -e:depends("target_function", "/opt") -e:depends("target_function", "/dev") -for i, d in ipairs(devices) do - if d.name and d.size then - e:value(d.name, "%s (%s, %d MB)" %{ d.name, d.dev, d.size }) - elseif d.name then - e:value(d.name, "%s (%s)" %{ d.name, d.dev }) - end -end - -e=t:option(Flag,"keep_config",translate("Keep configuration"),translate("Tick means to retain the settings")) -e:depends("target_function", "/overlay") -e:depends("target_function", "/") -e.default=0 - -e=t:option(ListValue,'format_type', translate('Format system type')) -e:depends("target_function", "/opt") -e:depends("target_function", "/dev") -e:value("0", translate("No formatting required")) -e:value("ext4", translate("Linux system partition(EXT4)")) -e:value("btrfs", translate("Large capacity storage devices(Btrfs)")) -e:value("ntfs", translate("Windows system partition(NTFS)")) -e.default="0" - -e=t:option(Button, "restart", translate("Perform operation")) -e.inputtitle=translate("Click to execute") -e.rawhtml=true -e.template ='partexp' - -return m diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexp.htm b/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexp.htm deleted file mode 100644 index eb22476994..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexp.htm +++ /dev/null @@ -1,130 +0,0 @@ -<%# -Copyright (C) 2022-2024 sirpdboy https://github.com/sirpdboy/partexp --%> -<%+cbi/valueheader%> -<%local fs=require"nixio.fs"%> - - - -<%+cbi/valuefooter%> diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexplog.htm b/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexplog.htm deleted file mode 100644 index b2b7b60f5b..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexplog.htm +++ /dev/null @@ -1,16 +0,0 @@ -<%+cbi/valueheader%> - - - -<%+cbi/valuefooter%> diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexplogrun.htm b/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexplogrun.htm deleted file mode 100644 index f42d6339f6..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/luasrc/view/partexplogrun.htm +++ /dev/null @@ -1,54 +0,0 @@ -<%+cbi/valueheader%> - -<%:Reverse%> - - - -<%+cbi/valuefooter%> \ No newline at end of file diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/po/templates/partexp.po b/openwrt-packages/luci-app-partexp/luci-app-partexp/po/templates/partexp.po new file mode 100644 index 0000000000..a621753ed5 --- /dev/null +++ b/openwrt-packages/luci-app-partexp/luci-app-partexp/po/templates/partexp.po @@ -0,0 +1,199 @@ +# Translation file for partexp.js +# Copyright (C) 2022-2025 Sirpdboy +# Licensed to the public under the Apache License 2.0 +# +msgid "" +msgstr "" +"Project-Id-Version: partexp\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: Chinese (Simplified)\n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Generated from partexp.js\n" + +#: JavaScript UI strings + +msgid "One click partition expansion mounting tool" +msgstr "" + +msgid "Automatically format and mount the target device partition. If there are multiple partitions, it is recommended to manually delete all partitions before using this tool." +msgstr "" + +msgid "For specific usage, see:" +msgstr "" + +msgid "Select function" +msgstr "" + +msgid "Used to extend to the root directory of EXT4 firmware(Ext4 /)" +msgstr "" + +msgid "Expand application space overlay (/overlay)" +msgstr "" + +msgid "Used as Docker data disk (/opt)" +msgstr "" + +msgid "Normal mount and use by device name(/mnt/x1)" +msgstr "" + +msgid "Select the function to be performed" +msgstr "" + +msgid "Destination hard disk" +msgstr "" + +msgid "Loading devices..." +msgstr "" + +msgid "Select the hard disk device to operate" +msgstr "" + +msgid "Keep configuration" +msgstr "" + +msgid "Tick means to retain the settings" +msgstr "" + +msgid "Format system type" +msgstr "" + +msgid "No formatting required" +msgstr "" + +msgid "Linux system partition(EXT4)" +msgstr "" + +msgid "Large capacity storage devices(Btrfs)" +msgstr "" + +msgid "Windows system partition(NTFS)" +msgstr "" + +msgid "Perform operation" +msgstr "" + +msgid "Click to execute" +msgstr "" + +msgid "Starting operation..." +msgstr "" + +msgid "Operation Log" +msgstr "" + +msgid "Are you sure you want to execute partition expansion?" +msgstr "" + +msgid "Function:" +msgstr "" + +msgid "Disk:" +msgstr "" + +msgid "Keep config:" +msgstr "" + +msgid "Format type:" +msgstr "" + +msgid "This operation may take several minutes." +msgstr "" + +msgid "Executing..." +msgstr "" + +msgid "Operation started successfully" +msgstr "" + +msgid "Operation failed" +msgstr "" + +msgid "Failed to start operation:" +msgstr "" + +msgid "Unknown error" +msgstr "" + +msgid "Operation in progress..." +msgstr "" + +msgid "Operation in progress..." +msgstr "" + +msgid "Operation in progress..." +msgstr "" + +msgid "Extend to root directory" +msgstr "" + +msgid "Expand overlay" +msgstr "" + +msgid "Docker data disk" +msgstr "" + +msgid "Normal mount" +msgstr "" + +msgid "No formatting" +msgstr "" + +msgid "Operation completed" +msgstr "" + +msgid "Getting device information" +msgstr "" + +msgid "Checking partition format" +msgstr "" + +msgid "Checking target device" +msgstr "" + +msgid "Locating target partition" +msgstr "" + +msgid "Checking free space" +msgstr "" + +msgid "Starting operation" +msgstr "" + +msgid "Initializing..." +msgstr "" + +msgid "Starting" +msgstr "" + +#: Device status messages +msgid "Loading device list..." +msgstr "" + +msgid "No devices found" +msgstr "" + +msgid "Failed to load devices" +msgstr "" + +msgid "Please select a target disk" +msgstr "" + +msgid "Settings saved" +msgstr "" + +msgid "Failed to save settings" +msgstr "" + +msgid "Loading saved configuration..." +msgstr "" + +msgid "Configuration loaded" +msgstr "" + +msgid "Failed to load configuration" +msgstr "" \ No newline at end of file diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/po/zh-cn/partexp.po b/openwrt-packages/luci-app-partexp/luci-app-partexp/po/zh-cn/partexp.po deleted file mode 100644 index 48d259e93d..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/po/zh-cn/partexp.po +++ /dev/null @@ -1,96 +0,0 @@ -msgid "" -msgstr "" -"Copyright (C) 2022-2025 sirpdboy herboy2008@gmail.com https://github.com/sirpdboy/luci-app-partexp" -"This is free software, licensed under the GNU General Public License v3." - -msgid "Partition Expansion" -msgstr "分区扩容" - -msgid "One click partition expansion mounting tool" -msgstr "一键分区扩容挂载工具" - -msgid "Automatically format and mount the target device partition. If there are multiple partitions, it is recommended to manually delete all partitions before using this tool.
For specific usage, see:" -msgstr "自动对目标设备分区格式化挂载,如果有多分区建议手动删除所有分区再使用本工具.
使用说明见:" - -msgid "Waiting,(executing)..." -msgstr "稍等,努力执行中" - -msgid "Expand application space overlay (/overlay)" -msgstr "用于overlay软件空间 (/overlay)" - -msgid "Used to extend to the root directory of EXT4 firmware(Ext4 /)" -msgstr "用于扩展为EXT4固件根目录(Ext4 /)" - -msgid "Used as Docker data disk (/opt)" -msgstr "用作Docker数据盘 (/opt)" - -msgid "Normal mount and use by device name(/mnt/x1)" -msgstr "按设备名普通挂载使用(/mnt/x1)" - -msgid "Soft chain partition expansion(/overlay)" -msgstr "分区软链扩容(/overlay)" - -msgid "Destination hard disk" -msgstr "目标硬盘" - -msgid "Keep configuration" -msgstr "保留配置" - -msgid "Format system type" -msgstr "格式化系统类型" - -msgid "No formatting required" -msgstr "不需要格式化" - -msgid "Linux system partition(EXT4)" -msgstr "Linux系统分区(EXT4)" - -msgid "Large capacity storage devices(Btrfs)" -msgstr "大容量存储设备(Btrfs)" - -msgid "Windows system partition(NTFS)" -msgstr "Windows系统分区(NTFS)" - -msgid "Select the hard disk device to operate" -msgstr "选择需要操作的硬盘设备" - -msgid "Select function" -msgstr "选择功能" - -msgid "Select the function to be performed" -msgstr "选择要执行的功能" - -msgid "Click to execute" -msgstr "点击执行" - -msgid "Perform operation" -msgstr "执行操作" - -msgid "To make the operation effective, the device will restart. Are you sure to execute?" -msgstr "警告:操作一旦确定无法取消,设备将会重启,是否确定执行?" - -msgid "Operation in progress, please wait..." -msgstr "操作执行中,请稍候..." - -msgid "After operation, restart the machine, please wait..." -msgstr "操作完毕,机器重启,请稍候..." - -msgid "Please delete the partition or share and try again" -msgstr "错误,请检查是否有足够空间或是共享使用中。" - -msgid "Restart the device to take effect. Confirm whether to continue?" -msgstr "重启设备操作才生效,确定是否继续执行?" - -msgid "Operation execution complete" -msgstr "操作执行完毕" - -msgid "Ticking indicates formatting" -msgstr "打勾选择表示格式化" - -msgid "Tick means to retain the settings" -msgstr "打勾选择表示保留设置" - -msgid "reverse" -msgstr "逆序" - - diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/po/zh_Hans/partexp.po b/openwrt-packages/luci-app-partexp/luci-app-partexp/po/zh_Hans/partexp.po index 48d259e93d..c12344a910 100644 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/po/zh_Hans/partexp.po +++ b/openwrt-packages/luci-app-partexp/luci-app-partexp/po/zh_Hans/partexp.po @@ -1,46 +1,72 @@ +# Translation file for partexp.js +# Copyright (C) 2022-2025 Sirpdboy +# Licensed to the public under the Apache License 2.0 +# msgid "" msgstr "" -"Copyright (C) 2022-2025 sirpdboy herboy2008@gmail.com https://github.com/sirpdboy/luci-app-partexp" -"This is free software, licensed under the GNU General Public License v3." +"Project-Id-Version: partexp\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: Chinese (Simplified)\n" +"Language: zh_Hans\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Generated from partexp.js\n" -msgid "Partition Expansion" -msgstr "分区扩容" +#: JavaScript UI strings msgid "One click partition expansion mounting tool" msgstr "一键分区扩容挂载工具" -msgid "Automatically format and mount the target device partition. If there are multiple partitions, it is recommended to manually delete all partitions before using this tool.
For specific usage, see:" -msgstr "自动对目标设备分区格式化挂载,如果有多分区建议手动删除所有分区再使用本工具.
使用说明见:" +msgid "Partition Expansion" +msgstr "分区扩容" -msgid "Waiting,(executing)..." -msgstr "稍等,努力执行中" +msgid "Automatically format and mount the target device partition. If there are multiple partitions, it is recommended to manually delete all partitions before using this tool." +msgstr "自动格式化并挂载目标设备分区。如果有多个分区,建议在使用此工具前手动删除所有分区。" -msgid "Expand application space overlay (/overlay)" -msgstr "用于overlay软件空间 (/overlay)" +msgid "For specific usage, see:" +msgstr "具体用法请参见:" + +msgid "Select function" +msgstr "选择功能" msgid "Used to extend to the root directory of EXT4 firmware(Ext4 /)" -msgstr "用于扩展为EXT4固件根目录(Ext4 /)" +msgstr "用于扩展到EXT4固件的根目录(Ext4 /)" + +msgid "Expand application space overlay (/overlay)" +msgstr "扩展应用空间overlay (/overlay)" msgid "Used as Docker data disk (/opt)" msgstr "用作Docker数据盘 (/opt)" msgid "Normal mount and use by device name(/mnt/x1)" -msgstr "按设备名普通挂载使用(/mnt/x1)" +msgstr "普通挂载并按设备名称使用(/mnt/x1)" -msgid "Soft chain partition expansion(/overlay)" -msgstr "分区软链扩容(/overlay)" +msgid "Select the function to be performed" +msgstr "选择要执行的功能" msgid "Destination hard disk" msgstr "目标硬盘" +msgid "Loading devices..." +msgstr "正在加载设备..." + +msgid "Select the hard disk device to operate" +msgstr "选择要操作的硬盘设备" + msgid "Keep configuration" msgstr "保留配置" +msgid "Tick means to retain the settings" +msgstr "勾选表示保留设置" + msgid "Format system type" msgstr "格式化系统类型" msgid "No formatting required" -msgstr "不需要格式化" +msgstr "无需格式化" msgid "Linux system partition(EXT4)" msgstr "Linux系统分区(EXT4)" @@ -51,46 +77,126 @@ msgstr "大容量存储设备(Btrfs)" msgid "Windows system partition(NTFS)" msgstr "Windows系统分区(NTFS)" -msgid "Select the hard disk device to operate" -msgstr "选择需要操作的硬盘设备" - -msgid "Select function" -msgstr "选择功能" - -msgid "Select the function to be performed" -msgstr "选择要执行的功能" +msgid "Perform operation" +msgstr "执行操作" msgid "Click to execute" msgstr "点击执行" -msgid "Perform operation" -msgstr "执行操作" +msgid "Starting operation..." +msgstr "正在启动操作..." -msgid "To make the operation effective, the device will restart. Are you sure to execute?" -msgstr "警告:操作一旦确定无法取消,设备将会重启,是否确定执行?" +msgid "Operation Log" +msgstr "操作日志" -msgid "Operation in progress, please wait..." -msgstr "操作执行中,请稍候..." +msgid "Are you sure you want to execute partition expansion?" +msgstr "确定要执行分区扩容吗?" -msgid "After operation, restart the machine, please wait..." -msgstr "操作完毕,机器重启,请稍候..." +msgid "Function:" +msgstr "功能:" -msgid "Please delete the partition or share and try again" -msgstr "错误,请检查是否有足够空间或是共享使用中。" +msgid "Disk:" +msgstr "磁盘:" -msgid "Restart the device to take effect. Confirm whether to continue?" -msgstr "重启设备操作才生效,确定是否继续执行?" +msgid "Keep config:" +msgstr "保留配置:" -msgid "Operation execution complete" -msgstr "操作执行完毕" +msgid "Format type:" +msgstr "格式化类型:" -msgid "Ticking indicates formatting" -msgstr "打勾选择表示格式化" +msgid "This operation may take several minutes." +msgstr "此操作可能需要几分钟时间。" -msgid "Tick means to retain the settings" -msgstr "打勾选择表示保留设置" +msgid "Executing..." +msgstr "正在执行..." -msgid "reverse" -msgstr "逆序" +msgid "Operation started successfully" +msgstr "操作启动成功" +msgid "Operation failed" +msgstr "操作失败" +msgid "Failed to start operation:" +msgstr "启动操作失败:" + +msgid "Unknown error" +msgstr "未知错误" + +msgid "Operation in progress..." +msgstr "操作正在进行中..." + +msgid "Operation in progress..." +msgstr "操作正在进行中..." + +msgid "Operation in progress..." +msgstr "操作正在进行中..." + +msgid "Extend to root directory" +msgstr "扩展到根目录" + +msgid "Expand overlay" +msgstr "扩展overlay" + +msgid "Docker data disk" +msgstr "Docker数据盘" + +msgid "Normal mount" +msgstr "普通挂载" + +msgid "No formatting" +msgstr "不格式化" + +msgid "Operation completed" +msgstr "操作完成" + +msgid "Getting device information" +msgstr "正在获取设备信息" + +msgid "Checking partition format" +msgstr "正在检查分区格式" + +msgid "Checking target device" +msgstr "正在检查目标设备" + +msgid "Locating target partition" +msgstr "正在定位目标分区" + +msgid "Checking free space" +msgstr "正在检查可用空间" + +msgid "Starting operation" +msgstr "正在开始操作" + +msgid "Initializing..." +msgstr "正在初始化..." + +msgid "Starting" +msgstr "开始" + +#: Device status messages +msgid "Loading device list..." +msgstr "正在加载设备列表..." + +msgid "No devices found" +msgstr "未找到设备" + +msgid "Failed to load devices" +msgstr "加载设备失败" + +msgid "Please select a target disk" +msgstr "请选择目标磁盘" + +msgid "Settings saved" +msgstr "设置已保存" + +msgid "Failed to save settings" +msgstr "保存设置失败" + +msgid "Loading saved configuration..." +msgstr "正在加载保存的配置..." + +msgid "Configuration loaded" +msgstr "配置已加载" + +msgid "Failed to load configuration" +msgstr "加载配置失败" \ No newline at end of file diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/config/partexp b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/config/partexp index 8ec8397ada..d2709c878e 100644 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/config/partexp +++ b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/config/partexp @@ -1,5 +1,5 @@ -config global 'global' - option target_function '/opt' - option target_disk '' - option keep_config '0' - option format_type '0' +config global 'global' + option target_function '/opt' + option target_disk '' + option keep_config '0' + option format_type '0' diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/init.d/partexp b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/init.d/partexp deleted file mode 100644 index 806a19bf18..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/init.d/partexp +++ /dev/null @@ -1,751 +0,0 @@ -#!/bin/sh /etc/rc.common - -# -# Copyright (C) 2021-2025 sirpdboy https://github.com/sirpdboy/luci-app-partexp - -# This is free software, licensed under the Apache License, Version 2.0 . -# - -START=99 -USE_PROCD=1 - -EXTRA_COMMANDS="autopart" - -CONFIG="taskplan" -LOCK=/var/lock/$CONFIG.lock -LOGD=/var/$CONFIG -LOGDIR=/etc/$CONFIG -LOG=$LOGDIR/bk$CONFIG.log - -[ -d "$LOGDIR" ] || mkdir -p $LOGDIR -[ -d "$LOGD" ] || mkdir -p $LOGD - -limit_log() { - local logf=$1 - [ ! -f "$logf" ] && return - local sc=100 - [ -n "$2" ] && sc=$2 - local count=$(grep -c "" $logf) - if [ $count -gt $sc ];then - let count=count-$sc - sed -i "1,$count d" $logf - fi -} - -init_env() { -[ ! -f "$LOG" ] && echo " " > $LOG - -} - - -gen_log()( - log "--自动分区扩展挂载开始执行-- " | tee -a $LOG -) - -log(){ - echo -e " $(date +'%Y-%m-%d %H:%M:%S') $*" | tee -a $LOG -} - -# 检查硬盘是否已挂载 -is_disk_mounted() { - DISK=$1 - if mount | grep -q "$DISK "; then - return 0 # 已挂载 - else - return 1 # 未挂载 - fi -} - - -mount_device() { - local DEVICE=$1 - local MOUNT_POINT=$2 - local TYPE=$3 - # 检查设备是否存在 - if [ ! -e "$DEVICE" ]; then - log "设备 $DEVICE 不存在" - return 1 - fi - - # 检查挂载点是否存在 - if [ ! -d "$MOUNT_POINT" ]; then - log "挂载点 $MOUNT_POINT 不存在,正在创建..." - mkdir -p "$MOUNT_POINT" - if [ $? -ne 0 ]; then - log "无法创建挂载点 $MOUNT_POINT" - return 1 - fi - fi - - # 检查设备是否已挂载 - if mount | grep -q "$DEVICE"; then - log "设备 $DEVICE 已挂载到其他位置" - return 1 - fi - - if mount | grep -q "$MOUNT_POINT"; then - log "挂载点 $MOUNT_POINT 已被其他设备占用" - return 1 - fi - - # 挂载设备 - log "正在挂载 $DEVICE 到 $MOUNT_POINT..." - # mount "$DEVICE" "$MOUNT_POINT" - - mount $TYPE "$DEVICE" "$MOUNT_POINT" >/dev/null 2> /dev/null - # 检查挂载是否成功 - if [ $? -eq 0 ]; then - log "挂载成功: $DEVICE -> $MOUNT_POINT" - return 0 - else - log "挂载失败: $DEVICE -> $MOUNT_POINT" - return 1 - fi -} - -# 取消硬盘挂载 -umount_disk() { - DISK=$1 - MOUNT='' - eval $(block info "$DISK" | grep -o -e "MOUNT=\S*") - if [ "$MOUNT" ]; then - umount $DISK 2>/dev/null - if [ $? -eq 0 ]; then - log "取消挂载成功:$DISK" - else - log "取消挂载失败:$DISK" - fi - else - log "设备/dev/$DISK未挂载" - fi -} - -# 从 block info 中提取指定字段的值 -get_block() { - local DISK=$1 - local TYPE=$2 - local value - value=`mount | grep $DISK |awk -F $TYPE '{print $2}' |awk '{print $1}' | head -1` - # value=$(block info "/dev/$DISK" | grep -o -e "$TYPE=\S*" | cut -d\" -f2) - echo $value -} - -# 检查是否有共享挂载(如 Samba 或 NFS) -check_shared_mount() { - DISK=$1 - if [ -f /etc/config/samba ]; then - SHARED=$(grep -q "/dev/$DISK" /etc/config/samba) - if [ $? -eq 0 ]; then - log "检测到 Samba 共享挂载: /dev/$DISK" - return 0 - fi - fi - # 检查是否有 NFS 共享 - if [ -f /etc/exports ]; then - SHARED=$(grep -q "/dev/$DISK" /etc/exports) - if [ $? -eq 0 ]; then - log "检测到 NFS 共享挂载: /dev/$DISK" - return 0 - fi - fi - return 1 -} - -usamba(){ -s=$1 -[ -e "/etc/config/$s" ] && { - msum=$(grep -c "config sambashare" /etc/config/$s) - for i in $(seq 0 $((msum)));do - pdev=`uci -q get $s.@sambashare[$i].path ` - [ "$pdev" = "$2" ] && { - uci delete $s.@sambashare[$i] - uci commit $s - log "分区/dev/$b被挂载$MOUNT共享使用,删除$s共享成功!" - sleep 5 - } - done -} - # 取消 Samba 共享 -if [ -f /etc/config/$s ]; then - sed -i "/\/dev\/$b/d" /etc/config/$s - /etc/init.d/$s restart -fi - # 取消 NFS 共享 -if [ -f /etc/exports ]; then - sed -i "/\/dev\/$b/d" /etc/exports - /etc/init.d/nfs restart -fi -} - - -is_disk_partitioned() { - PARTITION_COUNT=$(fdisk -l /dev/$1 2>/dev/null | grep -E "^/dev/$2" | wc -l) - if [[ "$PARTITION_COUNT" -gt 0 ]]; then - echo 1 - else - echo 0 - fi -} - -partednew(){ - DISK=$1 - parted -s /dev/$DISK mklabel gpt - parted -s /dev/$DISK mkpart primary ext4 1MiB -1 -} - -fdisknew(){ - echo -e "n\np\n\n\n\nw" | fdisk /dev/$1 >/dev/null 2> /dev/null -} - -fdisksave(){ - echo -e "n\w" | fdisk /dev/$1 >/dev/null 2> /dev/null -} - -# 格式化磁盘函数 DISK=/dev/sda1 ;TYPE=btrfs -format_disk() { - local DISK=$1 - local TYPE=$2 - [[ $TYPE == '0' || $TYPE == '' ]] && TYPE="ext4" - log "正在格式化 $DISK " - mkfs.$TYPE -F "$DISK" >/dev/null 2>/dev/null - if [ $? -eq 0 ]; then - log "格式化 $TYPE 成功 $DISK" - return 0 - else - log "格式化 $TYPE 失败 $DISK" - return 1 - fi -} - -fdiskB(){ - - a=$1 - b=$1$2 - log "开始检测目标$a信息" - log "检测/dev/$a是否需要分区和格式化$format_type" - block detect > /etc/config/fstab - uci -q set fstab.@global[0].anon_mount='0' - uci -q set fstab.@global[0].auto_mount='0' - uci commit fstab - if [ $target_function = '/opt' ] ;then - /etc/init.d/dockerd stop >/dev/null 2> /dev/null - amount=`mount |grep /opt | awk '{print $1}'` - if [ -n "$amount" ] ;then - umount $amount >/dev/null 2> /dev/null - log "取消/opt之前的挂载$amount成功!" - fi - for OPT in $(mount |grep /opt | awk '{print $3}');do - umount $OPT >/dev/null 2> /dev/null - log "取消/opt之前的挂载$OPT成功!" - done - fi - [ -d "/mnt/$b" ] || mkdir -p /mnt/$b - if is_disk_mounted "/dev/$b"; then - log "设备 /dev/$b 已挂载,尝试取消挂载..." - if check_shared_mount $b; then - usamba samba4 $MOUNT - usamba samba $MOUNT - sleep 5 - fi - umount_disk "/dev/$b" - [ $? -ne 0 ] || umount_disk "/mnt/$b" - else - log "设备/dev/$b未挂载" - isfdisk=0 - isP=$(is_disk_partitioned $a $b) - if [ "$isP" = '0' ] ;then - fdisksave $a - fdisknew $a - sleep 2 - isfdisk=1 - fi - isP=$(is_disk_partitioned $a $b) - if [[ "$isP" = '1' && "$isfdisk" = 1 ]] ;then - log "分区$b建立成功!" - elif [[ "$isP" = '1' && "$isfdisk" = 0 ]] ;then - log "检测目标分区$b已存在." - else - log "分区$b建立失败,请检查$b硬盘空间!" - expquit 1 - fi - sleep 1 - fi - if is_disk_mounted "/dev/$b"; then - umount /dev/$b >/dev/null 2> /dev/null - [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null - fi - if [[ "$target_function" = "/" || "$target_function" = "/overlay" ]] ; then - format_disk "/dev/$b" $format_type - elif [[ "$format_type" != "0" || "$isfdisk" = "1" ]] ; then - format_disk "/dev/$b" $format_type - else - log "设备/dev/$b如果未格式化,可能无法正常使用." - fi - - TYPE='';eval $(blkid "/dev/$b" | grep -o -e "TYPE=\S*") - - log "检测设备/dev/$b分区$TYPE格式!" - - if [ "$TYPE" = "ntfs" ];then - if [ `which ntfs-3g ` ] ;then - if is_disk_mounted "/mnt/$b" ;then - mount_device /dev/$b /mnt/$b "-t ntfs-3g" - fi - else - if is_disk_mounted "/mnt/$b" ;then - mount_device /dev/$b /mnt/$b "-t ntfs3" - fi - fi - else - mount /dev/$b /mnt/$b >/dev/null 2> /dev/null - fi - UUID='';eval $(block info /dev/$b | grep -o -e "UUID=\S*") - if [ ! "$UUID" ] ; then - log "获取/dev/$b设备UUID信息失败!" - expquit 1 - else - log "获取/dev/$b设备UUID信息:$UUID成功" - fi - case "$target_function" in - - "/overlay") - if [ "$keep_config" = "1" ] ; then - # cp -a -f /overlay/* /mnt/$b/ || cp -a -f /rom/overlay/* /mnt/$b/ - tar -C /overlay -cvf - . | tar -C /mnt/$b/ -xf - || tar -C /rom/overlay -cvf - . | tar -C /mnt/$b/ -xf - - umount /dev/$b >/dev/null 2> /dev/null - [ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null - [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null - block detect > /etc/config/fstab - OVERLAY=`uci -q get fstab.@mount[0].target ` - if [[ "$OVERLAY" = "/overlay" || "$OVERLAY" = "/dev/loop0" ]] ;then - uci -q set fstab.@mount[0].uuid="${UUID}" - uci -q set fstab.@mount[0].target='/overlay' - uci -q set fstab.@mount[0].enabled='0' - fi - msum=$(grep -c "'mount'" /etc/config/fstab) - for i in $(seq 0 $((msum-1))) - do - zuuid=`uci -q get fstab.@mount[$i].uuid ` - [ $? -ne 0 ] && break - if [ "$zuuid" = "$UUID" ] ; then - uci -q set fstab.@mount[$i].target="/overlay" - uci -q set fstab.@mount[$i].enabled='1' - fi - done - uci set fstab.@global[0].delay_root="15" - uci commit fstab - log "保留数据overlay扩展/dev/$b成功!" - eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") - echo $MOUNT $a>> /etc/partexppath - sleep 3 - log "设备重启才能生效" - expquit 2 - else - umount /dev/$b >/dev/null 2> /dev/null - [ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null - [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null - block detect > /etc/config/fstab - OVERLAY=`uci -q get fstab.@mount[0].target ` - if [[ "$OVERLAY" = "/overlay" || "$OVERLAY" = "/dev/loop0" ]] ;then - uci -q set fstab.@mount[0].uuid="${UUID}" - uci -q set fstab.@mount[0].target='/overlay' - uci -q set fstab.@mount[0].enabled='0' - fi - msum=$(grep -c "'mount'" /etc/config/fstab) - for i in $(seq 0 $((msum-1))) - do - zuuid=`uci -q get fstab.@mount[$i].uuid ` - [ $? -ne 0 ] && break - if [ "$zuuid" = "$UUID" ] ; then - uci -q set fstab.@mount[$i].target="/overlay" - uci -q set fstab.@mount[$i].enabled='1' - fi - done - uci set fstab.@global[0].delay_root="15" - uci commit fstab - log "不保留数据overlay扩展/dev/$b成功!" - eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") - echo $MOUNT $a>> /etc/partexppath - sleep 3 - log "设备重启才能生效" - expquit 2 - fi - ;; - "/opt") - umount /dev/$b >/dev/null 2> /dev/null - [ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null - [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null - block detect > /etc/config/fstab - mkdir -p $target_function - msum=$(grep -c "'mount'" /etc/config/fstab) - mount_device /dev/$b "$target_function" - for i in $(seq 0 $((msum-1))) - do - zuuid=`uci -q get fstab.@mount[$i].uuid ` - [ $? -ne 0 ] && break - if [ "$zuuid" = "$UUID" ] ; then - uci -q set fstab.@mount[$i].target="$target_function" - uci -q set fstab.@mount[$i].enabled='1' - fi - done - uci commit fstab - # ln -sf /mnt/$b /overlay - if is_disk_mounted "/opt"; then - log "/dev/$b分区扩容和挂载到$target_function成功!" - eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") - echo $MOUNT $a>> /etc/partexppath - log "如果没生效,请重启设备" - expquit 2 - else - log "/dev/$b分区扩容和挂载到$target_function失败!" - fi - ;; - "/") - - - ROOTBLK="$(readlink -f /sys/dev/block/"$(awk '$9="/dev/root"{print $3}' /proc/self/mountinfo)")" - [ -z "$ROOTBLK" ] && { log "错误:无法获取根分区块设备"; expquit 1; } - ROOTDISK="/dev/$(basename "${ROOTBLK%/}")" - FSTYPE=$(blkid -o value -s TYPE "$ROOTDISK" 2>/dev/null) - if [[ "$FSTYPE" != "squashfs" && -n "$FSTYPE" ]] ; then - if [ $target_function = '/' ] ;then - FREE_SPACE=$(check_free_space $(basename $DISK)) - log "目标盘 $ROOT_PART $FSTYPE有剩余空间: $FREE_SPACE Gb" - if [[ "$FREE_SPACE" -gt 2 ]]; then - rootpt_resize - expquit 2 - else - log "目标盘 $SYSTEM_DISK $FSTYPE没有足够的剩余空间!" - expquit 1 - fi - fi - if [ $target_function = '/overlay' ] ;then - FREE_SPACE=$(check_free_space $(basename $DISK)) - log "目标盘 $ROOT_PART $FSTYPE有剩余空间: $FREE_SPACE Gb" - if [[ "$FREE_SPACE" -gt 2 ]]; then - rootfs_resize - eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") - echo $MOUNT $a>> /etc/partexppath - expquit 2 - else - log "目标盘 $SYSTEM_DISK $FSTYPE没有足够的剩余空间!" - expquit 1 - fi - fi - else - log "目标硬盘不支持/根分区扩展!请换EXT4固件!" - fi - sleep 3 - expquit 2 - ;; - *) - umount /dev/$b >/dev/null 2> /dev/null - [ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null - [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null - block detect > /etc/config/fstab - mkdir -p $target_function - msum=$(grep -c "'mount'" /etc/config/fstab) - mount_device /dev/$b /mnt/$b - for i in $(seq 0 $((msum-1))) - do - zuuid=`uci -q get fstab.@mount[$i].uuid ` - [ $? -ne 0 ] && break - if [ "$zuuid" = "$UUID" ] ; then - uci -q set fstab.@mount[$i].target="/mnt/$b" - uci -q set fstab.@mount[$i].enabled='1' - fi - done - uci commit fstab - if is_disk_mounted /mnt/$b ; then - log "/dev/$b分区扩容和挂载到/mnt/$b成功!" - eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") - echo $MOUNT $a>> /etc/partexppath - log "如果没生效,请重启设备" - expquit 2 - else - log "/dev/$b分区扩容和挂载到/mnt/$b失败!" - fi - ;; - esac -} - -get_system_disk() { - SYSTEM_DISK=$(df -h | grep boot | awk '{print $1}' | head -1 | sed -E 's/(p?[0-9]+)$//') - [ -z ${SYSTEM_DISK} ] && SYSTEM_DISK=$(mount | grep 'on /overlay' | awk '{print $1}' | sed -E 's/(p?[0-9]+)$//' |head -1) - echo "$SYSTEM_DISK" - ROOT_DISK="/dev/$(basename "${ROOTBLK%/*}")" - echo "$ROOT_DISK" -} - -get_all_disks() { - DISKS=`find /dev -regex '.*/\(sd[a-z]\|mmcblk[0-9]\+\|sata[a-z]\|nvme[0-9]\+n[0-9]\+\|vd[a-z]\)$'` - echo "$DISKS" -} - -check_part_space() { - DISK=$1 - info=$(lsblk -no SIZE,FSTYPE,MOUNTPOINT "$DISK" | awk '{print $1}') - if [ -z "$info" ]; then - echo "物理大小: 未知(可能是未格式化的裸分区)" - else - echo $info |awk -F '.' '{print $1}' | sed 's/[A-Za-z]//g' - fi -} - -check_free_space() { - DISK=$1 - PARTED_OUTPUT=$(parted -s /dev/$DISK unit GB print free 2>/dev/null) - FREE_SPACE=$(echo "$PARTED_OUTPUT" | grep "Free Space" | awk '{print $3}' ) - echo $FREE_SPACE |awk -F '.' '{print $1}' | sed 's/[A-Za-z]//g' - -} - -show_partition_info() { - local partition="$1" - if [ ! -e "$partition" ]; then - echo "错误:分区 $partition 不存在!" - return 1 - fi - echo -e "\n=== 分区信息 [$partition] ===" - local lsblk_info=$(lsblk -no SIZE,FSTYPE,MOUNTPOINT "$partition" 2>/dev/null) - if [ -z "$lsblk_info" ]; then - echo "物理大小: 未知(可能是未格式化的裸分区)" - else - local size=$(echo "$lsblk_info" | awk '{print $1}') - local fstype=$(echo "$lsblk_info" | awk '{print $2}') - local mountpoint=$(echo "$lsblk_info" | awk '{print $3}') - echo "物理大小: $size" - echo "文件系统: ${fstype:-未知}" - echo "挂载点: ${mountpoint:-未挂载}" - fi - if df "$partition" &>/dev/null; then - local df_info=$(df -h "$partition" | awk 'NR=2 {print $2,$3,$4,$5}') - echo -e "\n[已挂载] 空间使用情况:" - echo "总容量: $(echo "$df_info" | awk '{print $1}')" - echo "已用: $(echo "$df_info" | awk '{print $2}')" - echo "剩余: $(echo "$df_info" | awk '{print $3}')" - echo "使用率: $(echo "$df_info" | awk '{print $4}')" - else - echo -e "\n[未挂载] 无法查询使用情况(需先挂载)" - fi - - local disk="${partition%[0-9]*}" - local part_num="${partition##*[!0-9]}" - echo -e "\n分区表信息:" - parted -s "$disk" unit MiB print | grep -w "^ $part_num" | awk '{print "起始: " $2 " MiB | 结束: " $3 " MiB | 类型: " $6}' -} - -get_next_partition_number() { - DISK=$1 - PARTITIONS=$(fdisk -l /dev/$DISK 2>/dev/null | grep -v boot | grep -E "^/dev/$DISK" | awk '{print $1}' | sed 's/\/dev\/[a-z]*//g' | awk -F '[^0-9]+' '{print $NF}') - MAX_PARTITION=$(echo "$PARTITIONS" | sort -n | tail -n 1) - NEXT_PARTITION=$(awk -v n="$MAX_PARTITION" 'BEGIN { print n + 1 }') - #NEXT_PARTITION=$((MAX_PARTITION + 1)) - echo "$NEXT_PARTITION" -} - - -get_last_partition_number() { - DISK=$1 - PARTITIONS=$(fdisk -l /dev/$DISK 2>/dev/null | grep -v boot | grep -E "^/dev/$DISK" | awk '{print $1}' | sed 's/\/dev\/[a-z]*//g' | awk -F '[^0-9]+' '{print $NF}') - MAX_PARTITION=$(echo "$PARTITIONS" | sort -n | tail -n 1) - echo "$MAX_PARTITION" -} - -get_partition_number() { - DISK=$1 - PARTITIONS=$(fdisk -l /dev/$DISK 2>/dev/null | grep -v boot | grep -E "^/dev/$DISK" | awk '{print $1}' | sed 's/\/dev\/[a-z]*//g' | wc -l) - echo "$PARTITIONS" -} - -rootpt_resize() -{ -if [ ! -e /etc/rootpt-resize ] ;then - log "--->请稍侯,系统根分区扩展中<---" - ROOTBLK="$(readlink -f /sys/dev/block/"$(awk -e '$9="/dev/root"{print $3}' /proc/self/mountinfo)")" - ROOTDISK="/dev/$(basename "${ROOTBLK%/}")" - ROOTPART="${ROOTBLK##*[^0-9]}" - partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' ) - log "--->根分区$ROOTDISK:$partplace <---" - sleep 3 - parted -f -s "${ROOTDISK}" resizepart "${ROOTPART}" 100% - mount_root done - touch /etc/rootpt-resize - sleep 3 - log "--->系统根分区扩展成功!<---" - partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' ) - log "--->根分区$ROOTDISK扩展后容量:$partplace <---" - log "--->如果没生效,请重启设备<---" - expquit 2 -else - log "已经扩展过或者挂载分区过,请删除分区或者重置重新操作或者联系作者sirpdboy!" - expquit 1 -fi -} - -rootfs_resize() -{ -if [ ! -e /etc/rootfs-resize ] && [ -e /etc/rootpt-resize ] ;then - log "--->请稍侯,系统根分区扩展中<---" - ROOTBLK="$(readlink -f /sys/dev/block/"$(awk -e '$9="/dev/root"{print $3}' /proc/self/mountinfo)")" - ROOTPART="${ROOTBLK##*[^0-9]}" - ROOTDISK="/dev/$(basename "${ROOTBLK%/}")" - partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' ) - log "--->根分区$ROOTDISK:$partplace <---" - sleep 3 - parted -f -s "${ROOTDISK}" resizepart "${ROOTPART}" 100% - mount_root done - touch /etc/rootpt-resize - sleep 3 - log "--->系统根分区扩展成功!<---" - partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' ) - log "--->根分区$ROOTDISK扩展后容量:$partplace <---" - log "--->请稍侯,系统overlay扩展中<---" - df -h /overlay | awk 'NR=2 {printf " overlay扩展前: 总容量: %s 已用: %s 剩余: %s 使用率: %s", $2, $3, $4, $5}' - LOOPDEV="$(awk -e '$5="/overlay"{print $9}' /proc/self/mountinfo)" - if [ -z "${LOOPDEV}" ] ; then - LOOP_DEV="$(losetup -f)" - losetup "${LOOPDEV}" "${ROOTDEV}" - fi - # eval $(blkid "$LOOPDEV" | grep -o -e "TYPE=\S*") - FSTYPE=$(blkid -o value -s TYPE "$LOOPDEV" 2>/dev/null) - umount -l /overlay - mount -t tmpfs -o size=128M tmpfs /overlay - losetup -d /dev/loop0 - losetup -fP ${ROOTDISK} - case "$FSTYPE" in - f2fs) - umount /overlay || { log "错误:无法卸载 /overlay"; expquit 1; } - fsck.f2fs -f "$LOOPDEV" - resize.f2fs -f "$LOOPDEV" || { log "错误:f2fs 调整大小失败"; expquit 1; } - ;; - ext4) - resize2fs -f "$LOOPDEV" || { log "错误:ext4 调整大小失败"; expquit 1; } - ;; - *) - log "--->分区格式 $FSTYPE 不识别,overlay 扩展失败!<---" - expquit 1 - ;; - esac - mount_root done - touch /etc/rootfs-resize - sleep 3 - log "--->系统overlay扩展成功!<---" - df -h /overlay | awk 'NR=2 {printf " overlay扩展后: 总容量: %s 已用: %s 剩余: %s 使用率: %s", $2, $3, $4, $5}' - log "--->如果没生效,请重启设备<---" - expquit 2 -else - log "已经扩展过或者挂载分区过,请删除分区或者重置重新操作或者联系作者sirpdboy!" - expquit 1 -fi -} - -get_config() { - config_get target_function $1 target_function 1 - config_get target_disk $1 target_disk 1 - config_get_bool keep_config $1 keep_config 1 - config_get format_type $1 format_type -} - -autopart() { - config_load partexp - config_foreach get_config global - touch $LOCK - init_env - gen_log - uci -q set fstab.@global[0].anon_mount='0' - uci -q set fstab.@global[0].auto_mount='0' - uci commit fstab - [ -e "/etc/config/dockerd" ] && /etc/init.d/dockerd stop >/dev/null 2> /dev/null - DISK=$target_disk - NEXTPART=1 - DISKSALL=$(get_all_disks) - DISK_COUNT=$(echo "$DISKSALL" | wc -l) - log "系统中检测到的硬盘数量: $DISK_COUNT" - log "硬盘信息列表:" $DISKSALL - SYSTEM_DISK=$(get_system_disk) - log "系统盘: "$SYSTEM_DISK - case "$SYSTEM_DISK" in - /dev/$DISK*) - - fdisksave /dev/$DISK - log "此次执行操作功能:$target_function ,目标盘是系统盘:/dev/$DISK" - - PARTITIONSUM=$(get_partition_number $DISK) - log "目标盘 $DISK 一共有分区数: $PARTITIONSUM个" - if [[ "$PARTITIONSUM" -gt 2 ]];then - FREE_SPACE=$(check_free_space $(basename $DISK)) - log "目标盘 $DISK 有剩余空间: $FREE_SPACE Gb" - if [[ "$FREE_SPACE" -gt 2 ]]; then - NEXTPART=$(get_next_partition_number $DISK) - else - NEXTPART=$(get_last_partition_number $DISK) - fi - else - FREE_SPACE=$(check_free_space $(basename $DISK)) - log "目标盘 $DISK 有剩余空间: $FREE_SPACE Gb" - if [[ "$FREE_SPACE" -gt 2 ]]; then - NEXTPART=$(get_next_partition_number $DISK) - else - - log "目标盘 $SYSTEM_DISK 没有足够的剩余空间!" - expquit 1 - fi - fi - ;; - *) - - log "此次执行操作功能:$target_function ,目标盘(非系统盘)是:/dev/$DISK" - PARTITIONSUM=$(get_partition_number $DISK) - log "目标盘 $DISK 一共有分区数: $PARTITIONSUM个" - if [[ "$PARTITIONSUM" -gt 1 ]];then - FREE_SPACE=$(check_free_space $(basename $DISK)) - log "目标盘 $DISK 有剩余空间: $FREE_SPACE Gb" - - [[ $FREE_SPACE -gt 2 ]] && NEXTPART=$(get_next_partition_number $DISK) || NEXTPART=$(get_last_partition_number $DISK) - else - NEXTPART=1 - fi - ;; - esac - log "定位到操作目标设备分区:/dev/$DISK$NEXTPART" - case "$DISK" in - vd*) fdiskB $DISK $NEXTPART;; - sd*) fdiskB $DISK $NEXTPART;; - nvme*) fdiskB $DISK p$NEXTPART;; - mmc*) fdiskB $DISK p$NEXTPART;; - *) - log "目标设备/dev/$DISK暂不支持!请联系作者sirpdboy!" - ;; - esac - expquit 1 -} - -start() { - - [ -f $LOCK ] && exit - [ x$xBOOT = x1 ] || autopart - rm -f $LOCK 2>/dev/null -} - -stop () { - - rm -f $LOCK 2>/dev/null - -} - -boot() { -xBOOT=1 start -} - -expquit() { - rm -f $LOCK - uci -q set fstab.@global[0].anon_mount='1' - uci -q set fstab.@global[0].auto_mount='1' - uci commit fstab - [ -e "/etc/config/dockerd" ] && /etc/init.d/dockerd restart >/dev/null 2> /dev/null - sleep 2 - [ $1 = 3 ] && log "重启中...\n" &&reboot - exit $1 -} - diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/partexp/lucilogpos b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/partexp/lucilogpos deleted file mode 100644 index a76eb9d7a5..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/partexp/lucilogpos +++ /dev/null @@ -1 +0,0 @@ -1043 \ No newline at end of file diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/partexp/partexp.log b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/partexp/partexp.log deleted file mode 100644 index 0ea6601819..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/partexp/partexp.log +++ /dev/null @@ -1 +0,0 @@ - 1 \ No newline at end of file diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/uci-defaults/40_luci-partexp b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/uci-defaults/40_luci-partexp deleted file mode 100644 index 9db7cc494b..0000000000 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/etc/uci-defaults/40_luci-partexp +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -chmod +x /etc/init.d/partexp >/dev/null 2>&1 -[ `uci -q get partexp.global` ] || uci set partexp.global=global -rm -rf /tmp/luci-modulecache /tmp/luci-indexcache* -exit 0 diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/bin/partexp b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/bin/partexp new file mode 100644 index 0000000000..a58d038516 --- /dev/null +++ b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/bin/partexp @@ -0,0 +1,809 @@ +#!/bin/sh + +# +# Copyright (C) 2021-2025 sirpdboy https://github.com/sirpdboy/luci-app-partexp +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +CONFIG="partexp" +LOCK=/var/lock/$CONFIG.lock +LOGD=/var/$CONFIG +LOG=$LOGD/bk$CONFIG.log + +[ -d "$LOGD" ] || mkdir -p $LOGD + + +init_env() { + [ ! -f "$LOG" ] && echo " " > $LOG +} + +gen_log() { + log " == 开始执行 == " | tee -a $LOG +} + +log(){ + echo -e " $(date +'%Y-%m-%d %H:%M:%S') $*" | tee -a $LOG +} + +logn(){ + echo -e " $*" | tee -a $LOG +} + +load_uci_config() { + if [ -f "/etc/config/$CONFIG" ]; then + target_function=$(uci -q get $CONFIG.global.target_function) + target_disk=$(uci -q get $CONFIG.global.target_disk) + keep_config=$(uci -q get $CONFIG.global.keep_config) + format_type=$(uci -q get $CONFIG.global.format_type) + + target_function="${target_function:-/opt}" + keep_config="${keep_config:-0}" + format_type="${format_type:-0}" + + return 0 + else + log "警告:配置文件不存在" + return 1 + fi +} + +is_disk_mounted() { + DISK=$1 + if mount | grep -q "$DISK "; then + return 0 + else + return 1 + fi +} + +mount_device() { + local DEVICE=$1 + local MOUNT_POINT=$2 + local TYPE=$3 + + if [ ! -e "$DEVICE" ]; then + log "设备 $DEVICE 不存在" + return 1 + fi + + if [ ! -d "$MOUNT_POINT" ]; then + log "挂载点 $MOUNT_POINT 不存在,正在创建..." + mkdir -p "$MOUNT_POINT" + if [ $? -ne 0 ]; then + log "无法创建挂载点 $MOUNT_POINT" + return 1 + fi + fi + + if mount | grep -q "$DEVICE"; then + log "设备 $DEVICE 已挂载到其他位置" + return 1 + fi + + if mount | grep -q "$MOUNT_POINT"; then + log "挂载点 $MOUNT_POINT 已被其他设备占用" + return 1 + fi + + log "正在挂载 $DEVICE 到 $MOUNT_POINT..." + + mount $TYPE "$DEVICE" "$MOUNT_POINT" >/dev/null 2> /dev/null + + if [ $? -eq 0 ]; then + log "挂载成功: $DEVICE -> $MOUNT_POINT" + return 0 + else + log "挂载失败: $DEVICE -> $MOUNT_POINT" + return 1 + fi +} + +# 取消硬盘挂载 +umount_disk() { + DISK=$1 + MOUNT='' + eval $(block info "$DISK" | grep -o -e "MOUNT=\S*") + if [ "$MOUNT" ]; then + umount $DISK 2>/dev/null + if [ $? -eq 0 ]; then + log "取消挂载:$DISK成功" + else + log "取消挂载:$DISK失败,请手动操作" + fi + else + log "设备/dev/$DISK未挂载" + fi +} + +# 从 block info 中提取指定字段的值 +get_block() { + local DISK=$1 + local TYPE=$2 + local value + value=`mount | grep $DISK |awk -F $TYPE '{print $2}' |awk '{print $1}' | head -1` + echo $value +} + +# 检查是否有共享挂载(如 Samba 或 NFS) +check_shared_mount() { + DISK=$1 + if [ -f /etc/config/samba ]; then + SHARED=$(grep -q "/dev/$DISK" /etc/config/samba) + if [ $? -eq 0 ]; then + log "检测到 Samba 共享挂载: /dev/$DISK" + return 0 + fi + fi + + if [ -f /etc/exports ]; then + SHARED=$(grep -q "/dev/$DISK" /etc/exports) + if [ $? -eq 0 ]; then + log "检测到 NFS 共享挂载: /dev/$DISK" + return 0 + fi + fi + return 1 +} + +usamba(){ + s=$1 + [ -e "/etc/config/$s" ] && { + msum=$(grep -c "config sambashare" /etc/config/$s) + for i in $(seq 0 $((msum)));do + pdev=`uci -q get $s.@sambashare[$i].path ` + [ "$pdev" = "$2" ] && { + uci delete $s.@sambashare[$i] + uci commit $s + log "分区/dev/$b被挂载$MOUNT共享使用,删除$s共享成功!" + sleep 5 + } + done + } + + if [ -f /etc/config/$s ]; then + sed -i "/\/dev\/$b/d" /etc/config/$s + /etc/init.d/$s restart + fi + + if [ -f /etc/exports ]; then + sed -i "/\/dev\/$b/d" /etc/exports + /etc/init.d/nfs restart + fi +} + +is_disk_partitioned() { + PARTITION_COUNT=$(fdisk -l /dev/$1 2>/dev/null | grep -E "^/dev/$2" | wc -l) + if [[ "$PARTITION_COUNT" -gt 0 ]]; then + echo 1 + else + echo 0 + fi +} + +partednew(){ + DISK=$1 + parted -s /dev/$DISK mklabel gpt + parted -s /dev/$DISK mkpart primary ext4 1MiB -1 +} + +fdisknew(){ + echo -e "n\np\n\n\n\nw" | fdisk /dev/$1 >/dev/null 2> /dev/null +} + +fdisksave(){ + echo -e "n\w" | fdisk /dev/$1 >/dev/null 2> /dev/null +} + +# 格式化磁盘函数 DISK=/dev/sda1 ;TYPE=btrfs +format_disk() { + local DISK=$1 + local TYPE=$2 + [[ $TYPE == '0' || $TYPE == '' ]] && TYPE="ext4" + log "正在格式化 $DISK " + mkfs.$TYPE -F "$DISK" >/dev/null 2>/dev/null + if [ $? -eq 0 ]; then + log "格式化 $TYPE 成功 $DISK" + return 0 + else + log "格式化 $TYPE 失败 $DISK" + return 1 + fi +} + + +# 获取系统盘 +get_system_disk() { + rom_dev=$(df -h | grep boot | awk '{print $1}' | head -1 ) + [ -z ${rom_dev} ] && rom_dev=`df -P /boot 2>/dev/null | awk 'NR==2 {print $1}'` + [ -z ${rom_dev} ] && rom_dev=`blkid -t TYPE="squashfs" |awk -F : '{print $1}'` + [ -z ${rom_dev} ] && TDISK=`lsblk -l -o NAME,MOUNTPOINTS | grep -E '/rom'| grep -v '/rom/' | head -1 | awk '{print $1}'` && rom_dev="/dev/$TDISK" + if [ -n "$rom_dev" ]; then + case "$rom_dev" in + /dev/sd[a-z][0-9]*) + disk=$(echo "$rom_dev" | sed 's/[0-9]*$//') + ;; + /dev/nvme[0-9]*n[0-9]*p[0-9]*) + disk=$(echo "$rom_dev" | sed 's/p[0-9]*$//') + ;; + /dev/mmcblk[0-9]*p[0-9]*) + disk=$(echo "$rom_dev" | sed 's/p[0-9]*$//') + ;; + /dev/vd[a-z][0-9]*) + disk=$(echo "$rom_dev" | sed 's/[0-9]*$//') + ;; + /dev/mtdblock*) + disk="$rom_dev" + ;; + /dev/ubiblock*) + disk="$rom_dev" + ;; + /dev/root) + # 特殊处理 /dev/root + disk=$(lsblk -no PKNAME / 2>/dev/null) + if [ -n "$disk" ]; then + disk="/dev/$disk" + fi + ;; + *) + # 尝试通用匹配 + if echo "$rom_dev" | grep -qE '^/dev/[a-z]+[0-9]+'; then + disk=$(echo "$rom_dev" | sed 's/[0-9]*$//') + fi + ;; + esac + fi + + if [ -n "$disk" ] && [ ! -b "$disk" ]; then + disk="" + fi + + echo "$disk" +} + +get_all_disks() { + DISKS=`find /dev -regex '.*/\(sd[a-z]\|mmcblk[0-9]\+\|sata[a-z]\|nvme[0-9]\+n[0-9]\+\|vd[a-z]\)$'` + echo "$DISKS" +} + +check_part_space() { + DISK=$1 + info=$(lsblk -no SIZE,FSTYPE,MOUNTPOINT "$DISK" | awk '{print $1}') + if [ -z "$info" ]; then + echo "物理大小: 未知(可能是未格式化的裸分区)" + else + echo $info |awk -F '.' '{print $1}' | sed 's/[A-Za-z]//g' + fi +} + +check_free_space() { + DISK=$1 + PARTED_OUTPUT=$(parted -s /dev/$DISK unit GB print free 2>/dev/null) + FREE_SPACE=$(echo "$PARTED_OUTPUT" | grep "Free Space" | awk '{print $3}' ) + echo $FREE_SPACE |awk -F '.' '{print $1}' | sed 's/[A-Za-z]//g' +} + +show_partition_info() { + local partition="$1" + if [ ! -e "$partition" ]; then + logn "错误:分区 $partition 不存在!" + return 1 + fi + logn " === 分区信息 [$partition] ===" + local lsblk_info=$(lsblk -no SIZE,FSTYPE,MOUNTPOINT "$partition" 2>/dev/null) + if [ -z "$lsblk_info" ]; then + logn "物理大小: 未知(可能是未格式化的裸分区)" + else + local size=$(echo "$lsblk_info" | awk '{print $1}') + local fstype=$(echo "$lsblk_info" | awk '{print $2}') + local mountpoint=$(echo "$lsblk_info" | awk '{print $3}') + logn "物理大小: $size 文件系统: ${fstype:-未知} 挂载点: ${mountpoint:-未挂载}" + fi + if df "$partition" &>/dev/null; then + local df_info=$(df -h "$partition" | tail -n 1 | awk 'NR=2 {print $2,$3,$4,$5}') + logn "[已挂载] 空间使用情况:" + logn "总容量: $(echo "$df_info" | awk '{print $1}') 已用: $(echo "$df_info" | awk '{print $2}') 剩余: $(echo "$df_info" | awk '{print $3}') 使用率: $(echo "$df_info" | awk '{print $4}')" + + else + logn "[未挂载] 无法查询使用情况(需先挂载)" + fi + + local disk="${partition%[0-9]*}" + local part_num="${partition##*[!0-9]}" + logn "分区表信息:" + logn `parted -s "$disk" unit MiB print | grep -w "^ $part_num" | awk '{print "起始: " $2 " MiB | 结束: " $3 " MiB | 类型: " $5}'` + +} + +get_next_partition_number() { + DISK=$1 + PARTITIONS=$(fdisk -l /dev/$DISK 2>/dev/null | grep -v boot | grep -E "^/dev/$DISK" | awk '{print $1}' | sed 's/\/dev\/[a-z]*//g' | awk -F '[^0-9]+' '{print $NF}') + MAX_PARTITION=$(echo "$PARTITIONS" | sort -n | tail -n 1) + NEXT_PARTITION=$(awk -v n="$MAX_PARTITION" 'BEGIN { print n + 1 }') + echo "$NEXT_PARTITION" +} + +get_last_partition_number() { + DISK=$1 + PARTITIONS=$(fdisk -l /dev/$DISK 2>/dev/null | grep -v boot | grep -E "^/dev/$DISK" | awk '{print $1}' | sed 's/\/dev\/[a-z]*//g' | awk -F '[^0-9]+' '{print $NF}') + MAX_PARTITION=$(echo "$PARTITIONS" | sort -n | tail -n 1) + echo "$MAX_PARTITION" +} + +get_partition_number() { + DISK=$1 + PARTITIONS=$(fdisk -l /dev/$DISK 2>/dev/null | grep -v boot | grep -E "^/dev/$DISK" | awk '{print $1}' | sed 's/\/dev\/[a-z]*//g' | wc -l) + echo "$PARTITIONS" +} + +rootpt_resize() { + if [ ! -e /etc/rootpt-resize ]; then + log "--->请稍侯,系统根分区扩展中<---" + ROOTBLK="$(readlink -f /sys/dev/block/"$(awk -e '$9="/dev/root"{print $3}' /proc/self/mountinfo)")" + ROOTDISK="/dev/$(basename "${ROOTBLK%/}")" + ROOTPART="${ROOTBLK##*[^0-9]}" + partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' ) + log "--->根分区$ROOTDISK:$partplace <---" + sleep 3 + parted -f -s "${ROOTDISK}" resizepart "${ROOTPART}" 100% + mount_root done + touch /etc/rootpt-resize + sleep 3 + log "--->系统根分区扩展成功!<---" + partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' ) + log "--->根分区$ROOTDISK扩展后容量:$partplace <---" + log "--->如果没生效,请重启设备<---" + expquit 2 + else + log "已经扩展过或者挂载分区过,请删除分区或者重置重新操作或者联系作者sirpdboy!" + expquit 1 + fi +} + +rootfs_resize() { + if [ ! -e /etc/rootfs-resize ] && [ -e /etc/rootpt-resize ]; then + log "--->请稍侯,系统根分区扩展中<---" + ROOTBLK="$(readlink -f /sys/dev/block/"$(awk -e '$9="/dev/root"{print $3}' /proc/self/mountinfo)")" + ROOTPART="${ROOTBLK##*[^0-9]}" + ROOTDISK="/dev/$(basename "${ROOTBLK%/}")" + partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' ) + log "--->根分区$ROOTDISK:$partplace <---" + sleep 3 + parted -f -s "${ROOTDISK}" resizepart "${ROOTPART}" 100% + mount_root done + touch /etc/rootpt-resize + sleep 3 + log "--->系统根分区扩展成功!<---" + partplace=$(fdisk -l 2>/dev/null | grep "$ROOTDISK" | awk '{print $5}' ) + log "--->根分区$ROOTDISK扩展后容量:$partplace <---" + log "--->请稍侯,系统overlay扩展中<---" + df -h /overlay | awk 'NR=2 {printf " overlay扩展前: 总容量: %s 已用: %s 剩余: %s 使用率: %s", $2, $3, $4, $5}' + LOOPDEV="$(awk -e '$5="/overlay"{print $9}' /proc/self/mountinfo)" + if [ -z "${LOOPDEV}" ]; then + LOOP_DEV="$(losetup -f)" + losetup "${LOOPDEV}" "${ROOTDEV}" + fi + + FSTYPE=$(blkid -o value -s TYPE "$LOOPDEV" 2>/dev/null) + umount -l /overlay + mount -t tmpfs -o size=128M tmpfs /overlay + losetup -d /dev/loop0 + losetup -fP ${ROOTDISK} + + case "$FSTYPE" in + f2fs) + umount /overlay || { log "错误:无法卸载 /overlay"; expquit 1; } + fsck.f2fs -f "$LOOPDEV" + resize.f2fs -f "$LOOPDEV" || { log "错误:f2fs 调整大小失败"; expquit 1; } + ;; + ext4) + resize2fs -f "$LOOPDEV" || { log "错误:ext4 调整大小失败"; expquit 1; } + ;; + *) + log "--->分区格式 $FSTYPE 不识别,overlay 扩展失败!<---" + expquit 1 + ;; + esac + + mount_root done + touch /etc/rootfs-resize + sleep 3 + log "--->系统overlay扩展成功!<---" + df -h /overlay | awk 'NR=2 {printf " overlay扩展后: 总容量: %s 已用: %s 剩余: %s 使用率: %s", $2, $3, $4, $5}' + log "--->如果没生效,请重启设备<---" + expquit 2 + else + log "已经扩展过或者挂载分区过,请删除分区或者重置重新操作或者联系作者sirpdboy!" + expquit 1 + fi +} + +get_config() { + config_get target_function $1 target_function 1 + config_get target_disk $1 target_disk 1 + config_get_bool keep_config $1 keep_config 1 + config_get format_type $1 format_type +} + +# 修改 fdiskB 函数,使用环境变量参数 +fdiskB() { + a=$1 + b=$1$2 + log "开始检测目标$a信息" + log "检测/dev/$a是否需要分区和格式化" + + block detect > /etc/config/fstab + uci -q set fstab.@global[0].anon_mount='0' + uci -q set fstab.@global[0].auto_mount='0' + uci commit fstab + + if [ "$target_function" = '/opt' ]; then + /etc/init.d/dockerd stop >/dev/null 2> /dev/null + amount=`mount |grep /opt | awk '{print $1}'` + if [ -n "$amount" ]; then + umount $amount >/dev/null 2> /dev/null + log "取消/opt之前的挂载$amount成功!" + fi + for OPT in $(mount |grep /opt | awk '{print $3}');do + umount $OPT >/dev/null 2> /dev/null + log "取消/opt之前的挂载$OPT成功!" + done + fi + + [ -d "/mnt/$b" ] || mkdir -p /mnt/$b + + if is_disk_mounted "/dev/$b"; then + log "设备 /dev/$b 已挂载,尝试取消挂载..." + if check_shared_mount $b; then + usamba samba4 $MOUNT + usamba samba $MOUNT + sleep 5 + fi + umount_disk "/dev/$b" + [ $? -ne 0 ] || umount_disk "/mnt/$b" + else + log "设备/dev/$b未挂载" + isfdisk=0 + isP=$(is_disk_partitioned $a $b) + if [ "$isP" = '0' ]; then + fdisksave $a + fdisknew $a + sleep 2 + isfdisk=1 + fi + isP=$(is_disk_partitioned $a $b) + if [[ "$isP" = '1' && "$isfdisk" = 1 ]]; then + log "分区$b建立成功!" + elif [[ "$isP" = '1' && "$isfdisk" = 0 ]]; then + log "检测目标分区$b已存在." + else + log "分区$b建立失败,请检查$b硬盘空间!" + expquit 1 + fi + sleep 1 + fi + + if is_disk_mounted "/dev/$b"; then + umount /dev/$b >/dev/null 2> /dev/null + [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null + fi + sleep 5 + if [[ "$target_function" = "/" || "$target_function" = "/overlay" ]]; then + format_disk "/dev/$b" $format_type + elif [[ "$format_type" != "0" || "$isfdisk" = "1" ]]; then + format_disk "/dev/$b" $format_type + else + log "设备/dev/$b如果未格式化,可能无法正常使用." + fi + + TYPE='' + eval $(blkid "/dev/$b" | grep -o -e "TYPE=\S*") + log "检测设备/dev/$b分区$TYPE格式!" + + sleep 1 + if [ "$TYPE" = "ntfs" ]; then + if [ `which ntfs-3g` ]; then + if is_disk_mounted "/mnt/$b"; then + mount_device /dev/$b /mnt/$b "-t ntfs-3g" + fi + else + if is_disk_mounted "/mnt/$b"; then + mount_device /dev/$b /mnt/$b "-t ntfs3" + fi + fi + else + mount /dev/$b /mnt/$b >/dev/null 2> /dev/null + fi + + sleep 1 + UUID='' + eval $(block info /dev/$b | grep -o -e "UUID=\S*") + if [ ! "$UUID" ]; then + log "获取/dev/$b设备UUID信息失败!" + expquit 1 + else + log "获取/dev/$b设备UUID信息成功!" + fi + + sleep 1 + case "$target_function" in + "/overlay") + if [ "$keep_config" = "1" ]; then + tar -C /overlay -cvf - . | tar -C /mnt/$b/ -xf - || tar -C /rom/overlay -cvf - . | tar -C /mnt/$b/ -xf - + umount /dev/$b >/dev/null 2> /dev/null + [ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null + [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null + block detect > /etc/config/fstab + OVERLAY=`uci -q get fstab.@mount[0].target` + if [[ "$OVERLAY" = "/overlay" || "$OVERLAY" = "/dev/loop0" ]]; then + uci -q set fstab.@mount[0].uuid="${UUID}" + uci -q set fstab.@mount[0].target='/overlay' + uci -q set fstab.@mount[0].enabled='0' + fi + msum=$(grep -c "'mount'" /etc/config/fstab) + for i in $(seq 0 $((msum-1))) + do + zuuid=`uci -q get fstab.@mount[$i].uuid` + [ $? -ne 0 ] && break + if [ "$zuuid" = "$UUID" ]; then + uci -q set fstab.@mount[$i].target="/overlay" + uci -q set fstab.@mount[$i].enabled='1' + fi + done + uci set fstab.@global[0].delay_root="15" + uci commit fstab + log "保留数据overlay扩展/dev/$b成功!" + eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") + echo $MOUNT $a> /etc/partexppath + log "扩容成功!可直接【在线升级】扩容升级了!" + show_partition_info /dev/$b + sleep 3 + + expquit 2 + else + umount /dev/$b >/dev/null 2> /dev/null + [ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null + [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null + block detect > /etc/config/fstab + OVERLAY=`uci -q get fstab.@mount[0].target` + if [[ "$OVERLAY" = "/overlay" || "$OVERLAY" = "/dev/loop0" ]]; then + uci -q set fstab.@mount[0].uuid="${UUID}" + uci -q set fstab.@mount[0].target='/overlay' + uci -q set fstab.@mount[0].enabled='0' + fi + msum=$(grep -c "'mount'" /etc/config/fstab) + for i in $(seq 0 $((msum-1))) + do + zuuid=`uci -q get fstab.@mount[$i].uuid` + [ $? -ne 0 ] && break + if [ "$zuuid" = "$UUID" ]; then + uci -q set fstab.@mount[$i].target="/overlay" + uci -q set fstab.@mount[$i].enabled='1' + fi + done + uci set fstab.@global[0].delay_root="15" + uci commit fstab + log "不保留数据overlay扩展/dev/$b成功!" + eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") + echo $MOUNT $a> /etc/partexppath + log "扩容成功!可直接【在线升级】扩容升级了!" + show_partition_info /dev/$b + sleep 3 + expquit 2 + fi + ;; + "/opt") + umount /dev/$b >/dev/null 2> /dev/null + [ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null + [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null + block detect > /etc/config/fstab + mkdir -p $target_function + msum=$(grep -c "'mount'" /etc/config/fstab) + mount_device /dev/$b "$target_function" + for i in $(seq 0 $((msum-1))) + do + zuuid=`uci -q get fstab.@mount[$i].uuid` + [ $? -ne 0 ] && break + if [ "$zuuid" = "$UUID" ]; then + uci -q set fstab.@mount[$i].target="$target_function" + uci -q set fstab.@mount[$i].enabled='1' + fi + done + uci commit fstab + if is_disk_mounted "/opt"; then + log "/dev/$b分区扩容和挂载到$target_function成功!" + eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") + echo $MOUNT $a> /etc/partexppath + log "扩容成功!可直接【在线升级】扩容升级了!" + show_partition_info /dev/$b + expquit 2 + else + log "/dev/$b分区扩容和挂载到$target_function失败!" + fi + ;; + "/") + ROOTBLK="$(readlink -f /sys/dev/block/"$(awk '$9="/dev/root"{print $3}' /proc/self/mountinfo)")" + [ -z "$ROOTBLK" ] && { log "错误:无法获取根分区块设备"; expquit 1; } + ROOTDISK="/dev/$(basename "${ROOTBLK%/}")" + FSTYPE=$(blkid -o value -s TYPE "$ROOTDISK" 2>/dev/null) + if [[ "$FSTYPE" != "squashfs" && -n "$FSTYPE" ]]; then + if [ "$target_function" = '/' ]; then + FREE_SPACE=$(check_free_space $(basename $DISK)) + log "目标盘 $ROOT_PART $FSTYPE有剩余空间: $FREE_SPACE Gb" + if [[ "$FREE_SPACE" -gt 2 ]]; then + rootpt_resize + expquit 2 + else + log "目标盘 $SYSTEM_DISK $FSTYPE没有足够的剩余空间!" + expquit 1 + fi + fi + if [ "$target_function" = '/overlay' ]; then + FREE_SPACE=$(check_free_space $(basename $DISK)) + log "目标盘 $ROOT_PART $FSTYPE有剩余空间: $FREE_SPACE Gb" + if [[ "$FREE_SPACE" -gt 2 ]]; then + rootfs_resize + eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") + log "/dev/$b分区扩容和挂载到$target_function成功!" + echo $MOUNT $a> /etc/partexppath + log "扩容成功!可直接【在线升级】扩容升级了!" + show_partition_info /dev/$b + expquit 2 + else + log "目标盘 $SYSTEM_DISK $FSTYPE没有足够的剩余空间!" + expquit 1 + fi + fi + else + log "目标硬盘不支持/根分区扩展!请换EXT4固件!" + fi + sleep 3 + expquit 2 + ;; + *) + umount /dev/$b >/dev/null 2> /dev/null + [ $? -ne 0 ] && umount /mnt/$b >/dev/null 2> /dev/null + [ $? -ne 0 ] && block umount /dev/$b >/dev/null 2> /dev/null + block detect > /etc/config/fstab + mkdir -p /mnt/$b + msum=$(grep -c "'mount'" /etc/config/fstab) + mount_device /dev/$b /mnt/$b + for i in $(seq 0 $((msum-1))) + do + zuuid=`uci -q get fstab.@mount[$i].uuid` + [ $? -ne 0 ] && break + if [ "$zuuid" = "$UUID" ]; then + uci -q set fstab.@mount[$i].target="/mnt/$b" + uci -q set fstab.@mount[$i].enabled='1' + fi + done + uci commit fstab + if is_disk_mounted /mnt/$b; then + log "/dev/$b分区扩容和挂载到/mnt/$b成功!" + eval $(block info /dev/$b | grep -o -e "MOUNT=\S*") + echo $MOUNT $a> /etc/partexppath + log "扩容成功!可直接【在线升级】扩容升级了!" + show_partition_info /dev/$b + expquit 2 + else + log "/dev/$b分区扩容和挂载到/mnt/$b失败!" + fi + ;; + esac +} + +autopart() { + + [ -f $LOCK ] && expquit 1 + if [ -f "/etc/config/$CONFIG" ]; then + target_function=$(uci -q get partexp.global.target_function) + target_disk=$(uci -q get partexp.global.target_disk) + keep_config=$(uci -q get partexp.global.keep_config) + format_type=$(uci -q get partexp.global.format_type) + export target_function="${target_function:-/opt}" + export keep_config="${keep_config:-0}" + export format_type="${format_type:-0}" + export target_disk="${target_disk:-sda}" + fi + touch $LOCK + init_env + gen_log + + uci -q set fstab.@global[0].anon_mount='0' + uci -q set fstab.@global[0].auto_mount='0' + uci commit fstab + + [ -e "/etc/config/dockerd" ] && /etc/init.d/dockerd stop >/dev/null 2> /dev/null + + DISK=${target_disk} + NEXTPART=1 + DISKSALL=$(get_all_disks) + DISK_COUNT=$(echo "$DISKSALL" | wc -l) + log "系统中检测到的硬盘数量: $DISK_COUNT" + log "硬盘信息列表:" $DISKSALL + + SYSTEM_DISK=$(get_system_disk) + log "系统盘: "$SYSTEM_DISK + + case "$SYSTEM_DISK" in + /dev/$DISK*) + fdisksave /dev/$DISK + log "操作功能:$target_function ,系统盘:/dev/$DISK" + + PARTITIONSUM=$(get_partition_number $DISK) + log "目标盘 $DISK 一共有分区数: $PARTITIONSUM个" + + if [[ "$PARTITIONSUM" -gt 2 ]]; then + FREE_SPACE=$(check_free_space $(basename $DISK)) + log "目标盘 $DISK 有剩余空间: $FREE_SPACE Gb" + if [[ "$FREE_SPACE" -gt 2 ]]; then + NEXTPART=$(get_next_partition_number $DISK) + else + NEXTPART=$(get_last_partition_number $DISK) + fi + else + FREE_SPACE=$(check_free_space $(basename $DISK)) + log "目标盘 $DISK 有剩余空间: $FREE_SPACE Gb" + if [[ "$FREE_SPACE" -gt 2 ]]; then + NEXTPART=$(get_next_partition_number $DISK) + else + log "目标盘 $SYSTEM_DISK 没有足够的剩余空间!" + expquit 1 + fi + fi + ;; + *) + log "操作功能:$target_function ,非系统盘:/dev/$DISK" + PARTITIONSUM=$(get_partition_number $DISK) + log "目标盘 $DISK 一共有分区数: $PARTITIONSUM个" + + if [[ "$PARTITIONSUM" -gt 1 ]]; then + FREE_SPACE=$(check_free_space $(basename $DISK)) + log "目标盘 $DISK 有剩余空间: $FREE_SPACE Gb" + [[ $FREE_SPACE -gt 2 ]] && NEXTPART=$(get_next_partition_number $DISK) || NEXTPART=$(get_last_partition_number $DISK) + else + NEXTPART=1 + fi + ;; + esac + + log "定位到操作目标设备分区:/dev/$DISK$NEXTPART" + + case "$DISK" in + vd*|sd*) fdiskB $DISK $NEXTPART;; + nvme*|mmc*) fdiskB $DISK p$NEXTPART;; + # mtdblock*|ubiblock*) fdiskB $DISK $NEXTPART;; + *) + log "目标设备/dev/$DISK暂不支持!请联系作者sirpdboy!" + ;; + esac + expquit 1 +} + + +stop() { + rm -f $LOCK 2>/dev/null +} + +expquit() { + rm -f $LOCK + uci -q set fstab.@global[0].anon_mount='1' + uci -q set fstab.@global[0].auto_mount='1' + uci commit fstab + [ -e "/etc/config/dockerd" ] && /etc/init.d/dockerd restart >/dev/null 2> /dev/null + [ "$1" = "2" ] && log "如果没生效,请重启设备" + sleep 1 + log "== 操作完成 ==" + [ "$1" = "3" ] && log "重启中...\n" && reboot + exit $1 +} + +case "$1" in + autopart) + "$1" + ;; + *) + echo "Usage: $0 {autopart}" + exit 1 + ;; +esac \ No newline at end of file diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/libexec/rpcd/partexp b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/libexec/rpcd/partexp new file mode 100644 index 0000000000..e8ba056abc --- /dev/null +++ b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/libexec/rpcd/partexp @@ -0,0 +1,228 @@ +#!/bin/sh +. /usr/share/libubox/jshn.sh + +# 分区扩展服务 +case "$1" in + list) + echo '{ + "autopart": { + "description": "Execute automatic partition expansion" + }, + "get_log": { + "description": "Get operation log", + "arguments": { + "position": "string" + } + }, + "get_devices": { + "description": "Get available disk devices" + }, + "get_status": { + "description": "Get operation status" + }, + "save_config": { + "description": "Save configuration", + "arguments": { + "target_function": "string", + "target_disk": "string", + "keep_config": "string", + "format_type": "string" + } + } + }' + ;; + call) + case "$2" in + autopart) + if [ -f "/var/run/partexp.lock" ]; then + echo '{"error": "Another operation is in progress"}' + return 1 + fi + + # 检查配置文件是否存在 + if [ ! -f "/etc/config/partexp" ]; then + echo '{"error": "Configuration file not found. Please save settings first."}' + return 1 + fi + + # 创建锁文件 + touch /var/run/partexp.lock + + # 执行分区操作(后台异步执行) + { + # 清空日志文件 + echo "" > /tmp/partexp.log + + # 调用原 partexp 脚本 + /usr/bin/partexp autopart > /tmp/partexp.log 2>&1 + + # 清理锁文件 + rm -f /var/run/partexp.lock + } & + + echo '{"success": true, "pid": "'$!'", "message": "Partition expansion started"}' + ;; + + get_log) + # 获取操作日志 + read input + json_load "$input" + json_get_vars position + + if [ ! -f "/tmp/partexp.log" ]; then + echo '{"log": "", "complete": true}' + return 0 + fi + + if [ -z "$position" ] || [ "$position" = "0" ]; then + # 从头读取 + log_content=$(cat /tmp/partexp.log 2>/dev/null | tail -c 2048000) + new_position=$(stat -c%s /tmp/partexp.log 2>/dev/null || echo "0") + + json_init + json_add_string "log" "$log_content" + json_add_boolean "complete" false + json_add_string "position" "$new_position" + json_dump + else + # 从指定位置读取 + position=${position:-0} + file_size=$(stat -c%s /tmp/partexp.log 2>/dev/null || echo 0) + + if [ "$position" -lt "$file_size" ]; then + log_content=$(tail -c +$((position + 1)) /tmp/partexp.log | head -c 2048000) + new_position=$((position + ${#log_content})) + + json_init + json_add_string "log" "$log_content" + json_add_boolean "complete" false + json_add_string "position" "$new_position" + json_dump + else + json_init + json_add_string "log" "" + json_add_boolean "complete" true + json_add_string "position" "$position" + json_dump + fi + fi + ;; + + get_devices) + # 获取可用设备列表 - 仅磁盘 + json_init + json_add_array "devices" + + # 所有可能的磁盘设备模式 + disk_patterns=" + ^sd[a-z]$ + ^mmcblk[0-9]+$ + ^nvme[0-9]+n[0-9]+$ + ^vd[a-z]$ + ^hd[a-z]$ + ^xvd[a-z]$ + ^ubd[a-z]+$ + ^dasd[a-z]+$ + ^cciss[0-9]+$ + ^ida[0-9]+$ + ^rd[0-9]+$ + ^mtdblock[0-9]+$ + ^nbd[0-9]+$ + ^zram[0-9]+$ + " + + for dev in /sys/class/block/*; do + dev_name=$(basename "$dev") + + # 跳过分区、loop、dm 设备 + if [ -f "$dev/partition" ] || [ -d "$dev/loop" ] || [ -d "$dev/dm" ]; then + continue + fi + + # 检查是否为磁盘设备 + is_disk=0 + for pattern in $disk_patterns; do + if echo "$dev_name" | grep -qE "$pattern"; then + is_disk=1 + break + fi + done + + if [ $is_disk -eq 1 ]; then + size="0" + if [ -f "$dev/size" ]; then + size_sectors=$(cat "$dev/size") + size=$((size_sectors / 2048)) + fi + + json_add_object + json_add_string "name" "$dev_name" + json_add_string "dev" "/dev/$dev_name" + json_add_int "size" "$size" + json_close_object + fi + done + + json_close_array + json_dump + ;; + + + get_status) + # 获取操作状态 + if [ -f "/var/run/partexp.lock" ]; then + echo '{"running": true}' + else + echo '{"running": false}' + fi + ;; + + + save_config) + # 保存配置 + read input + json_load "$input" + json_get_vars target_function target_disk keep_config format_type + + # 验证参数 + if [ -z "$target_function" ]; then + echo '{"error": "Missing target_function parameter"}' + return 1 + fi + + # 设置默认值 + target_disk="${target_disk:-}" + keep_config="${keep_config:-0}" + format_type="${format_type:-0}" + + # 构建配置内容 + CONFIG_FILE="/etc/config/partexp" + mkdir -p "$(dirname "$CONFIG_FILE")" + + cat > "$CONFIG_FILE" << EOF +# Auto-generated by partexp + +config global global + option target_function '$target_function' + option target_disk '$target_disk' + option keep_config '$keep_config' + option format_type '$format_type' +EOF + + if [ $? -eq 0 ]; then + echo '{"success": true, "message": "Configuration saved"}' + else + echo '{"error": "Failed to save configuration"}' + return 1 + fi + ;; + + *) + echo '{"error": "Method not found"}' + ;; + esac + ;; + *) + echo '{"error": "Invalid action"}' + ;; +esac \ No newline at end of file diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/share/luci/menu.d/luci-app-partexp.json b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/share/luci/menu.d/luci-app-partexp.json new file mode 100644 index 0000000000..39fdd8158d --- /dev/null +++ b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/share/luci/menu.d/luci-app-partexp.json @@ -0,0 +1,14 @@ +{ + "admin/system/partexp": { + "title": "Partition Expansion", + "order": 54, + "action": { + "type": "view", + "path": "partexp" + }, + "acl": ["luci-app-partexp"], + "depends": { + "acl": ["luci-app-partexp"] + } + } +} diff --git a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/share/rpcd/acl.d/luci-app-partexp.json b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/share/rpcd/acl.d/luci-app-partexp.json index 9003434018..20bf3550c9 100644 --- a/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/share/rpcd/acl.d/luci-app-partexp.json +++ b/openwrt-packages/luci-app-partexp/luci-app-partexp/root/usr/share/rpcd/acl.d/luci-app-partexp.json @@ -2,22 +2,18 @@ "luci-app-partexp": { "description": "Grant UCI access for luci-app-partexp", "read": { - "file": { - "/etc/init.d/partexp": [ "exec" ], - "/var/partexp": ["read"], - "/etc/partexppath": ["read"], - "/etc/partexp/": ["read"] - }, - "uci": [ "partexp" ] + "ubus": { + "file": ["exec", "list", "stat", "read"], + "uci": [ "*" ], + "partexp": ["*"] + } }, "write": { - "file": { - "/var/partexp": ["write"], - "/etc/partexppath": ["write"], - "/etc/partexp/": ["write"] - - }, - "uci": [ "partexp" ] - } + "ubus": { + "partexp": ["*"], + "file": ["write"], + "uci": ["*"] + } } -} + } +} \ No newline at end of file diff --git a/sing-box/adapter/dns.go b/sing-box/adapter/dns.go index 4e79d65711..bf73f4e5af 100644 --- a/sing-box/adapter/dns.go +++ b/sing-box/adapter/dns.go @@ -27,8 +27,6 @@ type DNSClient interface { Start() Exchange(ctx context.Context, transport DNSTransport, message *dns.Msg, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) (*dns.Msg, error) Lookup(ctx context.Context, transport DNSTransport, domain string, options DNSQueryOptions, responseChecker func(responseAddrs []netip.Addr) bool) ([]netip.Addr, error) - LookupCache(domain string, strategy C.DomainStrategy) ([]netip.Addr, bool) - ExchangeCache(ctx context.Context, message *dns.Msg) (*dns.Msg, bool) ClearCache() } diff --git a/sing-box/cmd/internal/update_certificates/main.go b/sing-box/cmd/internal/update_certificates/main.go index 744d77243f..55b221e1bb 100644 --- a/sing-box/cmd/internal/update_certificates/main.go +++ b/sing-box/cmd/internal/update_certificates/main.go @@ -17,6 +17,10 @@ func main() { if err != nil { log.Error(err) } + err = updateChromeIncludedRootCAs() + if err != nil { + log.Error(err) + } } func updateMozillaIncludedRootCAs() error { @@ -69,3 +73,94 @@ func init() { generated.WriteString("}\n") return os.WriteFile("common/certificate/mozilla.go", []byte(generated.String()), 0o644) } + +func fetchChinaFingerprints() (map[string]bool, error) { + response, err := http.Get("https://ccadb.my.salesforce-sites.com/ccadb/AllCertificateRecordsCSVFormatv4") + if err != nil { + return nil, err + } + defer response.Body.Close() + reader := csv.NewReader(response.Body) + header, err := reader.Read() + if err != nil { + return nil, err + } + countryIndex := slices.Index(header, "Country") + fingerprintIndex := slices.Index(header, "SHA-256 Fingerprint") + + chinaFingerprints := make(map[string]bool) + for { + record, err := reader.Read() + if err == io.EOF { + break + } else if err != nil { + return nil, err + } + if record[countryIndex] == "China" { + chinaFingerprints[record[fingerprintIndex]] = true + } + } + return chinaFingerprints, nil +} + +func updateChromeIncludedRootCAs() error { + chinaFingerprints, err := fetchChinaFingerprints() + if err != nil { + return err + } + + response, err := http.Get("https://ccadb.my.salesforce-sites.com/ccadb/RootCACertificatesIncludedByRSReportCSV") + if err != nil { + return err + } + defer response.Body.Close() + reader := csv.NewReader(response.Body) + header, err := reader.Read() + if err != nil { + return err + } + subjectIndex := slices.Index(header, "Subject") + statusIndex := slices.Index(header, "Google Chrome Status") + certIndex := slices.Index(header, "X.509 Certificate (PEM)") + fingerprintIndex := slices.Index(header, "SHA-256 Fingerprint") + + generated := strings.Builder{} + generated.WriteString(`// Code generated by 'make update_certificates'. DO NOT EDIT. + +package certificate + +import "crypto/x509" + +var chromeIncluded *x509.CertPool + +func init() { + chromeIncluded = x509.NewCertPool() +`) + for { + record, err := reader.Read() + if err == io.EOF { + break + } else if err != nil { + return err + } + if record[statusIndex] != "Included" { + continue + } + if chinaFingerprints[record[fingerprintIndex]] { + continue + } + generated.WriteString("\n // ") + generated.WriteString(record[subjectIndex]) + generated.WriteString("\n") + generated.WriteString(" chromeIncluded.AppendCertsFromPEM([]byte(`") + cert := record[certIndex] + // Remove single quotes if present + if len(cert) > 0 && cert[0] == '\'' { + cert = cert[1 : len(cert)-1] + } + generated.WriteString(cert) + generated.WriteString("`))\n") + } + generated.WriteString("}\n") + return os.WriteFile("common/certificate/chrome.go", []byte(generated.String()), 0o644) +} diff --git a/sing-box/common/certificate/chrome.go b/sing-box/common/certificate/chrome.go new file mode 100644 index 0000000000..8a361c6138 --- /dev/null +++ b/sing-box/common/certificate/chrome.go @@ -0,0 +1,2817 @@ +// Code generated by 'make update_certificates'. DO NOT EDIT. + +package certificate + +import "crypto/x509" + +var chromeIncluded *x509.CertPool + +func init() { + chromeIncluded = x509.NewCertPool() + + // CN=Actalis Authentication Root CA; O=Actalis S.p.A./03358520967; L=Milan; C=IT + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE-----`)) + + // CN=TunTrust Root CA; O=Agence Nationale de Certification Electronique; C=TN + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL +BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg +Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv +b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG +EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u +IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ +n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd +2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF +VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ +GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF +li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU +r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2 +eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb +MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg +jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB +7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW +5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE +ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0 +90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z +xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu +QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4 +FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH +22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP +xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn +dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5 +Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b +nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ +CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH +u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj +d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o= +-----END CERTIFICATE-----`)) + + // CN=Amazon Root CA 4; O=Amazon; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE-----`)) + + // CN=Amazon Root CA 1; O=Amazon; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE-----`)) + + // CN=Amazon Root CA 2; O=Amazon; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE-----`)) + + // CN=Amazon Root CA 3; O=Amazon; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE-----`)) + + // CN=Certum Trusted Network CA; OU=Certum Certification Authority; O=Unizeto Technologies S.A.; C=PL + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE-----`)) + + // CN=Certum EC-384 CA; OU=Certum Certification Authority; O=Asseco Data Systems S.A.; C=PL + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw +CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw +JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT +EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 +WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT +LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX +BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE +KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm +Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 +EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J +UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn +nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE-----`)) + + // CN=Certum Trusted Root CA; OU=Certum Certification Authority; O=Asseco Data Systems S.A.; C=PL + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 +MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu +MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV +BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw +MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg +U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ +n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q +p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq +NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF +8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 +HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa +mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi +7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF +ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P +qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ +v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 +Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD +ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 +WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo +zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR +5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ +GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf +5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq +0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D +P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM +qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP +0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf +E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE-----`)) + + // CN=Certum Trusted Network CA 2; OU=Certum Certification Authority; O=Unizeto Technologies S.A.; C=PL + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE-----`)) + + // CN=Autoridad de Certificacion Firmaprofesional CIF A62634068; C=ES + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1 +MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc +tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd +IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j +b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC +AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw +ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m +iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF +Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ +hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P +Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE +EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV +1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t +CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR +5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw +f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9 +ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK +GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV +-----END CERTIFICATE-----`)) + + // CN=ANF Secure Server Root CA; OU=ANF CA Raiz; O=ANF Autoridad de Certificacion; C=ES; SerialNumber=G63287510 + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV +BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk +YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV +BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN +MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF +UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD +VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v +dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj +cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q +yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH +2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX +H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL +zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR +p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz +W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/ +SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn +LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3 +n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B +u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj +o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC +AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L +9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej +rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK +pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0 +vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq +OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ +/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9 +2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI ++PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2 +MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo +tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw= +-----END CERTIFICATE-----`)) + + // CN=Buypass Class 2 Root CA; O=Buypass AS-983163327; C=NO + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE-----`)) + + // CN=Buypass Class 3 Root CA; O=Buypass AS-983163327; C=NO + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE-----`)) + + // CN=Certainly Root R1; O=Certainly; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw +PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy +dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 +YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 +1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT +vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed +aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 +1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 +r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 +cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ +wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ +6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA +2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH +Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR +eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u +d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr +PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi +1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd +rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di +taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 +lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj +yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn +Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy +yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n +wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 +OV+KmalBWQewLK8= +-----END CERTIFICATE-----`)) + + // CN=Certainly Root E1; O=Certainly; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw +CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu +bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ +BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s +eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK ++IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 +QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 +hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm +ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG +BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE-----`)) + + // CN=Certigna; O=Dhimyotis; C=FR + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE-----`)) + + // CN=Certigna Root CA; OU=0002 48146308100036; O=Dhimyotis; C=FR + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE-----`)) + + // OU=certSIGN ROOT CA; O=certSIGN; C=RO + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE-----`)) + + // OU=certSIGN ROOT CA G2; O=CERTSIGN SA; C=RO + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE-----`)) + + // CN=HiPKI Root CA - G1; O=Chunghwa Telecom Co., Ltd.; C=TW + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa +Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3 +YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw +qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv +Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6 +lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz +Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ +KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK +FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj +HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr +y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ +/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM +a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6 +fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG +SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi +7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc +SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza +ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc +XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg +iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho +L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF +Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr +kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ +vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU +YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== +-----END CERTIFICATE-----`)) + + // OU=ePKI Root Certification Authority; O=Chunghwa Telecom Co., Ltd.; C=TW + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE-----`)) + + // CN=D-TRUST BR Root CA 1 2020; O=D-Trust GmbH; C=DE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5 +NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS +zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0 +QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/ +VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW +wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV +dWNbFJWcHwHP2NVypw87 +-----END CERTIFICATE-----`)) + + // CN=D-TRUST EV Root CA 1 2020; O=D-Trust GmbH; C=DE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw +CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS +VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5 +NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG +A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC +/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD +wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3 +OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g +PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf +Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l +dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1 +c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO +PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA +y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb +gfM0agPnIjhQW+0ZT0MW +-----END CERTIFICATE-----`)) + + // CN=D-TRUST Root Class 3 CA 2 EV 2009; O=D-Trust GmbH; C=DE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE-----`)) + + // CN=D-TRUST Root Class 3 CA 2 2009; O=D-Trust GmbH; C=DE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE-----`)) + + // CN=T-TeleSec GlobalRoot Class 3; OU=T-Systems Trust Center; O=T-Systems Enterprise Services GmbH; C=DE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE-----`)) + + // CN=T-TeleSec GlobalRoot Class 2; OU=T-Systems Trust Center; O=T-Systems Enterprise Services GmbH; C=DE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE-----`)) + + // CN=DigiCert TLS RSA4096 Root G5; O=DigiCert, Inc.; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN +MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT +HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN +NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs +IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+ +ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0 +2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp +wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM +pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD +nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po +sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx +Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd +Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX +KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe +XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL +tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv +TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN +AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw +GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H +PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF +O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ +REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik +AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv +/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+ +p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw +MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF +qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK +ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+ +-----END CERTIFICATE-----`)) + + // CN=DigiCert TLS ECC P384 Root G5; O=DigiCert, Inc.; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp +Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2 +MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ +bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS +7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp +0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS +B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 +BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ +LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4 +DXZDjC5Ty3zfDBeWUA== +-----END CERTIFICATE-----`)) + + // CN=DigiCert Assured ID Root CA; OU=www.digicert.com; O=DigiCert Inc; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE-----`)) + + // CN=DigiCert Assured ID Root G2; OU=www.digicert.com; O=DigiCert Inc; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE-----`)) + + // CN=DigiCert Assured ID Root G3; OU=www.digicert.com; O=DigiCert Inc; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE-----`)) + + // CN=DigiCert Global Root CA; OU=www.digicert.com; O=DigiCert Inc; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE-----`)) + + // CN=DigiCert Global Root G2; OU=www.digicert.com; O=DigiCert Inc; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE-----`)) + + // CN=DigiCert Global Root G3; OU=www.digicert.com; O=DigiCert Inc; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE-----`)) + + // CN=DigiCert High Assurance EV Root CA; OU=www.digicert.com; O=DigiCert Inc; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE-----`)) + + // CN=DigiCert Trusted Root G4; OU=www.digicert.com; O=DigiCert Inc; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE-----`)) + + // CN=QuoVadis Root CA 2; O=QuoVadis Limited; C=BM + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE-----`)) + + // CN=QuoVadis Root CA 2 G3; O=QuoVadis Limited; C=BM + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE-----`)) + + // CN=QuoVadis Root CA 3 G3; O=QuoVadis Limited; C=BM + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE-----`)) + + // CN=CA Disig Root R2; O=Disig a.s.; L=Bratislava; C=SK + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE-----`)) + + // CN=emSign ECC Root CA - G3; OU=emSign PKI; O=eMudhra Technologies Limited; C=IN + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE-----`)) + + // CN=emSign Root CA - G1; OU=emSign PKI; O=eMudhra Technologies Limited; C=IN + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE-----`)) + + // CN=AffirmTrust Commercial; O=AffirmTrust; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE-----`)) + + // CN=Atos TrustedRoot 2011; O=Atos; C=DE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE-----`)) + + // CN=Atos TrustedRoot Root CA ECC TLS 2021; O=Atos; C=DE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w +LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w +CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0 +MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF +Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI +zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X +tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4 +AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2 +KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD +aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu +CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo +9H1/IISpQuQo +-----END CERTIFICATE-----`)) + + // CN=Atos TrustedRoot Root CA RSA TLS 2021; O=Atos; C=DE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM +MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx +MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00 +MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD +QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z +4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv +Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ +kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs +GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln +nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh +3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD +0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy +geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8 +ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB +c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI +pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS +4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs +o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ +qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw +xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM +rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4 +AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR +0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY +o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5 +dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE +oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ== +-----END CERTIFICATE-----`)) + + // CN=GlobalSign; OU=GlobalSign Root CA - R6; O=GlobalSign + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE-----`)) + + // CN=GlobalSign Root E46; O=GlobalSign nv-sa; C=BE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE-----`)) + + // CN=GlobalSign Root R46; O=GlobalSign nv-sa; C=BE + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE-----`)) + + // CN=GlobalSign; OU=GlobalSign ECC Root CA - R5; O=GlobalSign + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE-----`)) + + // CN=GlobalSign; OU=GlobalSign Root CA - R3; O=GlobalSign + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE-----`)) + + // CN=Starfield Root Certificate Authority - G2; O=Starfield Technologies, Inc.; L=Scottsdale; ST=Arizona; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE-----`)) + + // CN=Go Daddy Root Certificate Authority - G2; O=GoDaddy.com, Inc.; L=Scottsdale; ST=Arizona; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE-----`)) + + // CN=GlobalSign; OU=GlobalSign ECC Root CA - R4; O=GlobalSign + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD +VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw +MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g +UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx +uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV +HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ ++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 +bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE-----`)) + + // CN=GTS Root R4; O=Google Trust Services LLC; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE-----`)) + + // CN=GTS Root R2; O=Google Trust Services LLC; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt +nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY +6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu +MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k +RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg +f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV ++3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo +dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW +Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa +G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq +gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H +vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8 +0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC +B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u +NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg +yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev +HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6 +xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR +TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg +JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV +7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl +6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL +-----END CERTIFICATE-----`)) + + // CN=GTS Root R1; O=Google Trust Services LLC; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE-----`)) + + // CN=GTS Root R3; O=Google Trust Services LLC; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G +jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2 +4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7 +VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm +ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X +-----END CERTIFICATE-----`)) + + // CN=ACCVRAIZ1; OU=PKIACCV; O=ACCV; C=ES + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE-----`)) + + // OU=AC RAIZ FNMT-RCM; O=FNMT-RCM; C=ES + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE-----`)) + + // CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS; OU=Ceres; O=FNMT-RCM; C=ES; OrganizationIdentifier=VATES-Q2826004J + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw +CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw +FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S +Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 +MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL +DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS +QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH +sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK +Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu +SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC +MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy +v+c= +-----END CERTIFICATE-----`)) + + // CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1; OU=Kamu Sertifikasyon Merkezi - Kamu SM; O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK; L=Gebze - Kocaeli; C=TR + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE-----`)) + + // CN=HARICA TLS RSA Root CA 2021; O=Hellenic Academic and Research Institutions CA; C=GR + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs +MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg +Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL +MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl +YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv +b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l +mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE +4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv +a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M +pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw +Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b +LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY +AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB +AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq +E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr +W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ +CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU +X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3 +f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja +H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP +JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P +zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt +jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0 +/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT +BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79 +aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW +xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU +63ZTGI0RmLo= +-----END CERTIFICATE-----`)) + + // CN=HARICA TLS ECC Root CA 2021; O=Hellenic Academic and Research Institutions CA; C=GR + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw +CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh +cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v +dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG +A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj +aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg +Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7 +KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y +STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD +AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw +SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN +nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps +-----END CERTIFICATE-----`)) + + // CN=IdenTrust Commercial Root CA 1; O=IdenTrust; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE-----`)) + + // CN=ISRG Root X1; O=Internet Security Research Group; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE-----`)) + + // CN=ISRG Root X2; O=Internet Security Research Group; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw +CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg +R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00 +MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT +ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw +EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW ++1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9 +ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI +zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW +tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1 +/q4AaOeMSQ+2b1tbFfLn +-----END CERTIFICATE-----`)) + + // CN=Izenpe.com; O=IZENPE S.A.; C=ES + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE-----`)) + + // CN=SZAFIR ROOT CA2; O=Krajowa Izba Rozliczeniowa S.A.; C=PL + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE-----`)) + + // CN=e-Szigno Root CA 2017; O=Microsec Ltd.; L=Budapest; C=HU; OrganizationIdentifier=VATHU-23584497 + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE-----`)) + + // CN=Microsec e-Szigno Root CA 2009; O=Microsec Ltd.; L=Budapest; C=HU; EmailAddress=info@e-szigno.hu + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE-----`)) + + // CN=Microsoft ECC Root Certificate Authority 2017; O=Microsoft Corporation; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE-----`)) + + // CN=Microsoft RSA Root Certificate Authority 2017; O=Microsoft Corporation; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE-----`)) + + // CN=NAVER Global Root Certification Authority; O=NAVER BUSINESS PLATFORM Corp.; C=KR + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM +BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG +T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx +CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD +b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA +iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH +38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE +HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz +kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP +szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq +vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf +nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG +YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo +0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a +CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K +AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I +36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN +qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj +cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm ++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL +hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe +lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 +p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 +piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR +LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX +5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO +dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul +9XXeifdy +-----END CERTIFICATE-----`)) + + // CN=NetLock Arany (Class Gold) Főtanúsítvány; OU=Tanúsítványkiadók (Certification Services); O=NetLock Kft.; L=Budapest; C=HU + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE-----`)) + + // CN=OISTE WISeKey Global Root GC CA; OU=OISTE Foundation Endorsed; O=WISeKey; C=CH + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE-----`)) + + // CN=OISTE WISeKey Global Root GB CA; OU=OISTE Foundation Endorsed; O=WISeKey; C=CH + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE-----`)) + + // CN=Security Communication ECC RootCA1; O=SECOM Trust Systems CO.,LTD.; C=JP + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT +AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD +VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx +NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT +HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5 +IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl +dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK +ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu +9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O +be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k= +-----END CERTIFICATE-----`)) + + // OU=Security Communication RootCA2; O=SECOM Trust Systems CO.,LTD.; C=JP + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE-----`)) + + // CN=Entrust Root Certification Authority; OU=www.entrust.net/CPS is incorporated by reference, (c) 2006 Entrust, Inc.; O=Entrust, Inc.; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE-----`)) + + // CN=Sectigo Public Server Authentication Root E46; O=Sectigo Limited; C=GB + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw +CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T +ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN +MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG +A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT +ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC +WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+ +6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B +Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa +qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q +4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw== +-----END CERTIFICATE-----`)) + + // CN=COMODO ECC Certification Authority; O=COMODO CA Limited; L=Salford; ST=Greater Manchester; C=GB + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE-----`)) + + // CN=COMODO Certification Authority; O=COMODO CA Limited; L=Salford; ST=Greater Manchester; C=GB + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIID0DCCArigAwIBAgIQIKTEf93f4cdTYwcTiHdgEjANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xMTAxMDEwMDAw +MDBaFw0zMDEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo0IwQDAdBgNVHQ4EFgQUC1jli8ZMFTekQKkwqSG+RzZaVv8w +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBAC/JxBwHO89hAgCx2SFRdXIDMLDEFh9sAIsQrK/xR9SuEDwMGvjUk2ysEDd8 +t6aDZK3N3w6HM503sMZ7OHKx8xoOo/lVem0DZgMXlUrxsXrfViEGQo+x06iF3u6X +HWLrp+cxEmbDD6ZLLkGC9/3JG6gbr+48zuOcrigHoSybJMIPIyaDMouGDx8rEkYl +Fo92kANr3ryqImhrjKGsKxE5pttwwn1y6TPn/CbxdFqR5p2ErPioBhlG5qfpqjQi +pKGfeq23sqSaM4hxAjwu1nqyH6LKwN0vEJT9s4yEIHlG1QXUEOTS22RPuFvuG8Ug +R1uUq27UlTMdphVx8fiUylQ5PsE= +-----END CERTIFICATE-----`)) + + // CN=COMODO RSA Certification Authority; O=COMODO CA Limited; L=Salford; ST=Greater Manchester; C=GB + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE-----`)) + + // CN=USERTrust RSA Certification Authority; O=The USERTRUST Network; L=Jersey City; ST=New Jersey; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE-----`)) + + // CN=USERTrust ECC Certification Authority; O=The USERTRUST Network; L=Jersey City; ST=New Jersey; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE-----`)) + + // CN=Sectigo Public Server Authentication Root R46; O=Sectigo Limited; C=GB + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD +Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw +HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY +MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp +YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa +ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz +SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf +iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X +ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 +IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS +VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE +SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu ++Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt +8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L +HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt +zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P +AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ +YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 +gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA +Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB +JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX +DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui +TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 +dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 +LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp +0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY +QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE-----`)) + + // CN=Entrust Root Certification Authority - G2; OU=See www.entrust.net/legal-terms, (c) 2009 Entrust, Inc. - for authorized use only; O=Entrust, Inc.; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE-----`)) + + // CN=Entrust Root Certification Authority - EC1; OU=See www.entrust.net/legal-terms, (c) 2012 Entrust, Inc. - for authorized use only; O=Entrust, Inc.; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE-----`)) + + // CN=SSL.com Root Certification Authority RSA; O=SSL Corporation; L=Houston; ST=Texas; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE-----`)) + + // CN=SSL.com TLS ECC Root CA 2022; O=SSL Corporation; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT +U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 +MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh +dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm +acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN +SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME +GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW +uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp +15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN +b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== +-----END CERTIFICATE-----`)) + + // CN=SSL.com TLS RSA Root CA 2022; O=SSL Corporation; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD +DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX +DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP +L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY +t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins +S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 +PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO +L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 +R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w +dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS ++YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS +d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG +AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f +gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z +NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM +QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf +R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ +DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW +P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy +lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq +bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w +AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q +r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji +Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU +98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE-----`)) + + // CN=SSL.com Root Certification Authority ECC; O=SSL Corporation; L=Houston; ST=Texas; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE-----`)) + + // CN=SSL.com EV Root Certification Authority RSA R2; O=SSL Corporation; L=Houston; ST=Texas; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE-----`)) + + // CN=SSL.com EV Root Certification Authority ECC; O=SSL Corporation; L=Houston; ST=Texas; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE-----`)) + + // CN=SwissSign Gold CA - G2; O=SwissSign AG; C=CH + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE-----`)) + + // CN=TWCA CYBER Root CA; OU=Root CA; O=TAIWAN-CA; C=TW + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ +MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290 +IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5 +WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FO +LUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1sTs6P +40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxF +avcokPFhV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/ +34bKS1PE2Y2yHer43CdTo0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684i +JkXXYJndzk834H/nY62wuFm40AZoNWDTNq5xQwTxaWV4fPMf88oon1oglWa0zbfu +j3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK/c/WMw+f+5eesRycnupf +Xtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkHIuNZW0CP +2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDA +S9TMfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDA +oS/xUgXJP+92ZuJF2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzC +kHDXShi8fgGwsOsVHkQGzaRP6AzRwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW +5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83QOGt4A1WNzAd +BgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB +AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0t +tGlTITVX1olNc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn +68xDiBaiA9a5F/gZbG0jAn/xX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNn +TKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDRIG4kqIQnoVesqlVYL9zZyvpoBJ7t +RCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq/p1hvIbZv97Tujqx +f36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0RFxbI +Qh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz +8ppy6rBePm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4 +NxKfKjLji7gh7MMrZQzvIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzX +xeSDwWrruoBa3lwtcHb4yOWHh8qgnaHlIhInD0Q9HWzq1MKLL295q39QpsQZp6F6 +t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X +-----END CERTIFICATE-----`)) + + // CN=TWCA Global Root CA; OU=Root CA; O=TAIWAN-CA; C=TW + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE-----`)) + + // CN=TeliaSonera Root CA v1; O=TeliaSonera + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE-----`)) + + // CN=Telia Root CA v2; O=Telia Finland Oyj; C=FI + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx +CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE +AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1 +NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ +MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq +AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9 +vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9 +lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD +n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT +7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o +6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC +TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6 +WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R +DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI +pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj +YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy +rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ +8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi +0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM +A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS +SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K +TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF +6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er +3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt +Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT +VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW +ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA +rBPuUBQemMc= +-----END CERTIFICATE-----`)) + + // CN=Trustwave Global ECC P384 Certification Authority; O=Trustwave Holdings, Inc.; L=Chicago; ST=Illinois; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB +BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ +j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF +1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G +A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 +AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC +MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu +Sw== +-----END CERTIFICATE-----`)) + + // CN=Trustwave Global ECC P256 Certification Authority; O=Trustwave Holdings, Inc.; L=Chicago; ST=Illinois; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN +FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w +DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw +CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh +DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE-----`)) + + // CN=SecureTrust CA; O=SecureTrust Corporation; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE-----`)) + + // CN=Trustwave Global Certification Authority; O=Trustwave Holdings, Inc.; L=Chicago; ST=Illinois; C=US + chromeIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw +CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x +ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 +c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx +OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI +SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn +swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu +7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 +1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW +80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP +JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l +RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw +hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 +coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc +BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n +twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W +0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe +uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q +lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB +aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE +sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT +MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe +qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh +VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 +h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 +EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK +yeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE-----`)) +} diff --git a/sing-box/common/certificate/mozilla.go b/sing-box/common/certificate/mozilla.go index 097091d0bc..a5db7267f2 100644 --- a/sing-box/common/certificate/mozilla.go +++ b/sing-box/common/certificate/mozilla.go @@ -710,104 +710,6 @@ Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+ vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ== ------END CERTIFICATE-----`)) - - // CommScope Public Trust ECC Root-01 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw -TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t -bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa -Fw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv -cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLxeP0C -flfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJE -hRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq -hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg -2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS -Um9poIyNStDuiw7LR47QjRE= ------END CERTIFICATE-----`)) - - // CommScope Public Trust ECC Root-02 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw -TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t -bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa -Fw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv -cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/MMDAL -j2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmU -v4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq -hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n -ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV -mkzw5l4lIhVtwodZ0LKOag== ------END CERTIFICATE-----`)) - - // CommScope Public Trust RSA Root-01 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQEL -BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi -Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1 -NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t -U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt -MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45FtnYSk -YZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslh -suitQDy6uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0al -DrJLpA6lfO741GIDuZNqihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3Oj -WiE260f6GBfZumbCk6SP/F2krfxQapWsvCQz0b2If4b19bJzKo98rwjyGpg/qYFl -P8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/cZip8UlF1y5mO6D1cv547 -KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTifBSeolz7p -UcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/ -kQO9lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JO -Hg9O5j9ZpSPcPYeoKFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkB -Ea801M/XrmLTBQe0MXXgDW1XT2mH+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6U -CBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm45P3luG0wDQYJ -KoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6 -NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQ -nmhUQo8mUuJM3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+ -QgvfKNmwrZggvkN80V4aCRckjXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2v -trV0KnahP/t1MJ+UXjulYPPLXAziDslg+MkfFoom3ecnf+slpoq9uC02EJqxWE2a -aE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/WNyVntHKLr4W96ioD -j8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+o/E4 -Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0w -lREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn -YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVoc -icCMb3SgazNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw ------END CERTIFICATE-----`)) - - // CommScope Public Trust RSA Root-02 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQEL -BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi -Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2 -NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t -U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt -MDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3VrCLE -NQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0 -kyI9p+Kx7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1C -rWDaSWqVcN3SAOLMV2MCe5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxz -hkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2WWy09X6GDRl224yW4fKcZgBzqZUPckXk2 -LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rpM9kzXzehxfCrPfp4sOcs -n/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIfhs1w/tku -FT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5 -kQMreyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3 -wNemKfrb3vOTlycEVS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6v -wQcQeKwRoi9C8DfF8rhW3Q5iLc4tVn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs -5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7GxcJXvYXowDQYJ -KoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB -KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3 -+VGXu6TwYofF1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbyme -APnCKfWxkxlSaRosTKCL4BWaMS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3Nyq -pgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xdgSGn2rtO/+YHqP65DSdsu3BaVXoT -6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2OHG1QAk8mGEPej1WF -sQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+NmYWvt -PjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2d -lklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670 -v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17O -rg3bhzjlP1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7 -----END CERTIFICATE-----`)) // SecureSign Root CA12 @@ -1277,29 +1179,6 @@ L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm dTdmQRCsu/WU48IxK63nI1bMNSWSs1A= ------END CERTIFICATE-----`)) - - // Baltimore CyberTrust Root - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp -----END CERTIFICATE-----`)) // DigiCert Assured ID Root CA @@ -1587,6 +1466,180 @@ cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE-----`)) + + // QuoVadis Root CA 1 G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE-----`)) + + // QuoVadis Root CA 2 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE-----`)) + + // QuoVadis Root CA 2 G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE-----`)) + + // QuoVadis Root CA 3 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE-----`)) + + // QuoVadis Root CA 3 G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 -----END CERTIFICATE-----`)) // DIGITALSIGN GLOBAL ROOT ECDSA CA @@ -1878,147 +1931,6 @@ A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== ------END CERTIFICATE-----`)) - - // Entrust Root Certification Authority - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 -Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW -KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw -NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw -NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy -ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV -BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo -Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 -4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 -KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI -rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi -94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB -sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi -gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo -kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE -vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA -A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t -O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua -AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP -9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ -eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m -0vdXcDazv/wor3ElhVsT/h5/WrQ8 ------END CERTIFICATE-----`)) - - // Entrust Root Certification Authority - EC1 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG -A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 -d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu -dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq -RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy -MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD -VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 -L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g -Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi -A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt -ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH -Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O -BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC -R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX -hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G ------END CERTIFICATE-----`)) - - // Entrust Root Certification Authority - G2 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 -cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs -IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz -dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy -NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu -dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt -dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 -aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T -RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN -cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW -wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 -U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 -jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN -BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ -jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ -Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v -1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R -nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH -VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== ------END CERTIFICATE-----`)) - - // Entrust Root Certification Authority - G4 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw -gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL -Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg -MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw -BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 -MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 -c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ -bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg -Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ -2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E -T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j -5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM -C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T -DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX -wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A -2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm -nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 -dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl -N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj -c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS -5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS -Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr -hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ -B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI -AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw -H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ -b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk -2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol -IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk -5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY -n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== ------END CERTIFICATE-----`)) - - // Entrust.net Certification Authority (2048) - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML -RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 -IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 -MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 -LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp -YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG -A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq -K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe -sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX -MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT -XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ -HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH -4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub -j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo -U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf -zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b -u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ -bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er -fF6adulZkMV8gzURZVE= -----END CERTIFICATE-----`)) // Atos TrustedRoot 2011 @@ -3267,6 +3179,106 @@ bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE-----`)) + + // OISTE Client Root ECC G1 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICNDCCAbqgAwIBAgIQVOyX1ou0xAshbg6y0FPIejAKBggqhkjOPQQDAzBLMQsw +CQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwY +T0lTVEUgQ2xpZW50IFJvb3QgRUNDIEcxMB4XDTIzMDUzMTE0MzE0MFoXDTQ4MDUy +NDE0MzEzOVowSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRp +b24xITAfBgNVBAMMGE9JU1RFIENsaWVudCBSb290IEVDQyBHMTB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABIhOaB/Jnr46BFsVwzX0zFDFCK04bqg80gK6zKsl/XVA/WcZ +nxsKXfbLFnv5XB6C3BVE1Jw8bWGTRfRPz2K53z5TjZrUSt6Iqgum8dRh1h501Riy +xU1M74B77A3rgzlUlqNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSZ +Vzs5sS0AjCFmjJVpnG117Iw/+jAdBgNVHQ4EFgQUmVc7ObEtAIwhZoyVaZxtdeyM +P/owDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMQCW/+SCThYiW6CF +GDw9Oo8gBggl5/WRNhmte7TfW2YSN3Nw7c0FKAdeCM4NQl8ZkQICMGdJh64GQR0g +0zGmqiY38SeKYQ3+mgZDpy6eJkejMhiL6F5QBfGwekh23tuhYkq6dw== +-----END CERTIFICATE-----`)) + + // OISTE Client Root RSA G1 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIQNBdvWQGIG6ql3chIu7Q7czANBgkqhkiG9w0BAQwFADBL +MQswCQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UE +AwwYT0lTVEUgQ2xpZW50IFJvb3QgUlNBIEcxMB4XDTIzMDUzMTE0MjMyOVoXDTQ4 +MDUyNDE0MjMyOFowSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5k +YXRpb24xITAfBgNVBAMMGE9JU1RFIENsaWVudCBSb290IFJTQSBHMTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBALpP/v5UE7WEPLzg0zHxHW7cxFNx+uQ5 +UUN2fZIfgX8Aa0HC5trcGE1sF1lwCTNi7GmILbDdWflhYGBW8ba07+uH0BP+w89v +j345WFGziQKOVJUeIl+rKAVDJ/hF9AlCJpT+vRN4u5HyEBCcDWd82mQg63owGrpI +DXhUKpkxNKvLpmrnDGc5ZqQmqCco5/PmPHPkK8xvMS4TdGHLaObSM85SvH5lJFoh +gTFDqrKc0RjnYTxSr4CJ6TRG3vlNmVptHb3GJdGTVY74J5JDOoyVRUDjiRinhsFZ +mMrbJhwTwIyBuZiwrWmtbhjje2JB9a02/gu0eyBfn6lu+ZmCElLSisRUeLR890Gb +A+cHXrPCuUlkZ5IWxGCQDrCCfTOt0Dbq0XZrfIhHmKwb+bRQjGGBadgx8436PvL1 +S6/Owx3vXygb6xjWoFhSMr5Cb81JlyLBcLnT42BP3oOCoE4wvXNTwr0X/aDAmI/q +DhcH5kOVIE7bEaj549O4J0cMJ9sS64FVzHXbn9MXQ8T764oobemvRFBaQ/vxOeKT +UM+Y/ESWWDilpe1Fw1JCBafv5TykrD3n1qlWBaqww6cZ5OU911dEbZQRH8pwyPy5 +TMxBWoN0U5B4z9bULk+xqk0u9dEIWzpk78inqHph7Oym1YhOtlTUWJHCJWSRvAoU +PZIUmrULBukvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU +KYIlNQo6vpIr5AkD5OyPjThyOcswHQYDVR0OBBYEFCmCJTUKOr6SK+QJA+Tsj404 +cjnLMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQwFAAOCAgEAbSOGwv/14MjA +VYpgMcyXQ0dwQ9Pj7FL608Ke+4kyGspGk08Elyvb0JyEDZUHQlT+72kh35IDLo83 +ISN3qXc3bKDErpynWDlKFZdiRoNRIO0/wqPxw2In0KwTHv48Uh2Q1WPxqV7qf+fn +65ZaUezUqRvjDJRmrMuIkkm+c1yK4Gq8poHNs1zUI5LITfkgjHCUS2ht8o8ebDX3 +6F/U170gN1Jm/yu7SWa3cagsX3MPB5LnTl+lBtvJijyXxULqfQ+BG1frngwP/6Mn +IElTprM6TMttMDXa8vCa/lDfbVwkPU13an2GX0zQ4aa0rgQTAZDxgGiEB5SCB4Pr +keWTDnWRrqMjIElk1Lo5lldw7lU0KHzWr8qpnubJAckHwdBEsYC0UVCqj/ac5Wdz +0BvqgzUXL1DG3lbHu6MDy+KhGOj4zlEGo9IDQGEap2dXg/zRErkoqtpOa9Wc2IU3 +2r0i1zRZnBqmznjWlHgHBg+xkyGgSccQngquUXca+XGQw62YD4opamABqk+tIAMt +ao6jC2rW/ZMMimHLvSjxX3H9uDM51krx9rJoUj5lj0OdgSQk9ihMNaf9MwqleMEE +H+xJasSu1UQWpqeNf9ohlj6ouhZn1Kmh58Ka+BDZO5ruaPYvAO7Lu2aNIjiG9L9f +eKnIoB1au3VQ+VILDx0CLBQa84dqd/M= +-----END CERTIFICATE-----`)) + + // OISTE Server Root ECC G1 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICNTCCAbqgAwIBAgIQI/nD1jWvjyhLH/BU6n6XnTAKBggqhkjOPQQDAzBLMQsw +CQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UEAwwY +T0lTVEUgU2VydmVyIFJvb3QgRUNDIEcxMB4XDTIzMDUzMTE0NDIyOFoXDTQ4MDUy +NDE0NDIyN1owSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5kYXRp +b24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IEVDQyBHMTB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABBcv+hK8rBjzCvRE1nZCnrPoH7d5qVi2+GXROiFPqOujvqQy +cvO2Ackr/XeFblPdreqqLiWStukhEaivtUwL85Zgmjvn6hp4LrQ95SjeHIC6XG4N +2xml4z+cKrhAS93mT6NjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBQ3 +TYhlz/w9itWj8UnATgwQb0K0nDAdBgNVHQ4EFgQUN02IZc/8PYrVo/FJwE4MEG9C +tJwwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2kAMGYCMQCpKjAd0MKfkFFR +QD6VVCHNFmb3U2wIFjnQEnx/Yxvf4zgAOdktUyBFCxxgZzFDJe0CMQCSia7pXGKD +YmH5LVerVrkR3SW+ak5KGoJr3M/TvEqzPNcum9v4KGm8ay3sMaE641c= +-----END CERTIFICATE-----`)) + + // OISTE Server Root RSA G1 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIQVaXZZ5Qoxu0M+ifdWwFNGDANBgkqhkiG9w0BAQwFADBL +MQswCQYDVQQGEwJDSDEZMBcGA1UECgwQT0lTVEUgRm91bmRhdGlvbjEhMB8GA1UE +AwwYT0lTVEUgU2VydmVyIFJvb3QgUlNBIEcxMB4XDTIzMDUzMTE0MzcxNloXDTQ4 +MDUyNDE0MzcxNVowSzELMAkGA1UEBhMCQ0gxGTAXBgNVBAoMEE9JU1RFIEZvdW5k +YXRpb24xITAfBgNVBAMMGE9JU1RFIFNlcnZlciBSb290IFJTQSBHMTCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKqu9KuCz/vlNwvn1ZatkOhLKdxVYOPM +vLO8LZK55KN68YG0nnJyQ98/qwsmtO57Gmn7KNByXEptaZnwYx4M0rH/1ow00O7b +rEi56rAUjtgHqSSY3ekJvqgiG1k50SeH3BzN+Puz6+mTeO0Pzjd8JnduodgsIUzk +ik/HEzxux9UTl7Ko2yRpg1bTacuCErudG/L4NPKYKyqOBGf244ehHa1uzjZ0Dl4z +O8vbUZeUapU8zhhabkvG/AePLhq5SvdkNCncpo1Q4Y2LS+VIG24ugBA/5J8bZT8R +tOpXaZ+0AOuFJJkk9SGdl6r7NH8CaxWQrbueWhl/pIzY+m0o/DjH40ytas7ZTpOS +jswMZ78LS5bOZmdTaMsXEY5Z96ycG7mOaES3GK/m5Q9l3JUJsJMStR8+lKXHiHUh +sd4JJCpM4rzsTGdHwimIuQq6+cF0zowYJmXa92/GjHtoXAvuY8BeS/FOzJ8vD+Ho +mnqT8eDI278n5mUpezbgMxVz8p1rhAhoKzYHKyfMeNhqhw5HdPSqoBNdZH702xSu ++zrkL8Fl47l6QGzwBrd7KJvX4V84c5Ss2XCTLdyEr0YconosP4EmQufU2MVshGYR +i3drVByjtdgQ8K4p92cIiBdcuJd5z+orKu5YM+Vt6SmqZQENghPsJQtdLEByFSnT +kCz3GkPVavBpAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU +8snBDw1jALvsRQ5KH7WxszbNDo0wHQYDVR0OBBYEFPLJwQ8NYwC77EUOSh+1sbM2 +zQ6NMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQwFAAOCAgEANGd5sjrG5T33 +I3K5Ce+SrScfoE4KsvXaFwyihdJ+klH9FWXXXGtkFu6KRcoMQzZENdl//nk6HOjG +5D1rd9QhEOP28yBOqb6J8xycqd+8MDoX0TJD0KqKchxRKEzdNsjkLWd9kYccnbz8 +qyiWXmFcuCIzGEgWUOrKL+mlSdx/PKQZvDatkuK59EvV6wit53j+F8Bdh3foZ3dP +AGav9LEDOr4SfEE15fSmG0eLy3n31r8Xbk5l8PjaV8GUgeV6Vg27Rn9vkf195hfk +gSe7BYhW3SCl95gtkRlpMV+bMPKZrXJAlszYd2abtNUOshD+FKrDgHGdPY3ofRRs +YWSGRqbXVMW215AWRqWFyp464+YTFrYVI8ypKVL9AMb2kI5Wj4kI3Zaq5tNqqYY1 +9tVFeEJKRvwDyF7YZvZFZSS0vod7VSCd9521Kvy5YhnLbDuv0204bKt7ph6N/Ome +/msVuduCmsuY33OhkKCgxeDoAaijFJzIwZqsFVAzje18KotzlUBDJvyBpCpfOZC3 +J8tRd/iWkx7P8nd9H0aTolkelUTFLXVksNb54Dxp6gS1HAviRkRNQzuXSXERvSS2 +wq1yVAb+axj5d9spLFKebXd7Yv0PTY6YMjAwcRLWJTXjn/hvnLXrahut6hDTlhZy +BiElxky8j3C7DOReIoMt0r7+hVu05L0= -----END CERTIFICATE-----`)) // OISTE WISeKey Global Root GA CA @@ -3334,180 +3346,6 @@ BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV 57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 ------END CERTIFICATE-----`)) - - // QuoVadis Root CA 1 G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 -MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV -wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe -rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 -68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh -4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp -UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o -abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc -3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G -KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt -hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO -Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt -zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD -ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC -MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 -cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN -qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 -YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv -b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 -8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k -NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj -ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp -q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt -nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD ------END CERTIFICATE-----`)) - - // QuoVadis Root CA 2 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE-----`)) - - // QuoVadis Root CA 2 G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 -MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf -qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW -n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym -c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ -O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 -o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j -IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq -IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz -8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh -vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l -7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG -cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD -ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 -AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC -roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga -W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n -lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE -+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV -csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd -dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg -KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM -HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 -WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M ------END CERTIFICATE-----`)) - - // QuoVadis Root CA 3 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM -V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB -4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr -H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd -8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv -vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT -mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe -btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc -T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt -WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ -c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A -4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD -VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG -CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 -aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw -czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G -A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg -Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 -7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem -d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd -+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B -4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN -t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x -DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 -k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s -zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j -Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT -mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK -4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE-----`)) - - // QuoVadis Root CA 3 G3 - mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 -MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR -/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu -FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR -U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c -ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR -FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k -A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw -eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl -sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp -VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q -A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ -ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD -ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px -KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI -FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv -oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg -u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP -0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf -3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl -8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ -DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN -PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ -ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 -----END CERTIFICATE-----`)) // Security Communication ECC RootCA1 @@ -3655,6 +3493,147 @@ S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl 0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB NVOFBkpdn627G190 +-----END CERTIFICATE-----`)) + + // Entrust Root Certification Authority + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE-----`)) + + // Entrust Root Certification Authority - EC1 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE-----`)) + + // Entrust Root Certification Authority - G2 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE-----`)) + + // Entrust Root Certification Authority - G4 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE-----`)) + + // Entrust.net Certification Authority (2048) + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= -----END CERTIFICATE-----`)) // Sectigo Public Email Protection Root E46 @@ -4053,6 +4032,74 @@ hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE-----`)) + + // SwissSign RSA SMIME Root CA 2022 - 1 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFlzCCA3+gAwIBAgIURg7UAXGQoBqDLEpCECgV0mEbrTIwDQYJKoZIhvcNAQEL +BQAwUzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEtMCsGA1UE +AxMkU3dpc3NTaWduIFJTQSBTTUlNRSBSb290IENBIDIwMjIgLSAxMB4XDTIyMDYw +ODEwNTMxM1oXDTQ3MDYwODEwNTMxM1owUzELMAkGA1UEBhMCQ0gxFTATBgNVBAoT +DFN3aXNzU2lnbiBBRzEtMCsGA1UEAxMkU3dpc3NTaWduIFJTQSBTTUlNRSBSb290 +IENBIDIwMjIgLSAxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1Pv6 +P4aimXAJOsnWoU4Bzka1LSRIDUXprMka1zKApObTytbyKTfsmizWgc7mG52xD0Hf +WNNfqqB5WQuMrfnF+Rz7w+k1QHTDwQzLZ/ucXgwj+dAv+kyCRRy19R/4GW7ak7dO +aIN+Yi0djJUfcNnOWowhXai+CKlWbdn3uZCZxzvXvZ4uyWdXLiHO8DKD+wQB+beC +RA2yy3oJoUg+T8ALahsb7M8dnn8GkKwoBQuo5lQ7oqcsOROZqPs06/XwvQHYiBHI +rroZAkkC3IostL1hYOydeFxqiy8Xhl7yT5MAa13FsqmlGOrmbX5XBfsH/Lx8oUOx +ZhyoZ/urN/aqqrh6Qfc51YyfrnI2J+RixkOZ8aFB6f+Jnw9Jr8kUBhcnZDkNpbQq +W+w8+5/FX8Y7XSYZ8oQpuJVECVL9bDDQYo8opYGWK5QvJnXkCYwK3zjzfl04joKa +jNyers4SQjoi8jWNT9IayEkzC/o2P/8sa2ogcUzNrRA/aTKEjlzuU4hE4t3MAzCS +hnmQKkt1+1JixPRvTffbI6EY3UVTF5pjJEiJIs1+mwEcgCgDj1sr+h/jfBm95o+x +QHag8sc3sjKUEDLNpxOX8TssejQie3Q6QOKvgvjBwXj8X+Q1f8D0TPBMsuqHA3Il +WYMqCKRR3s/uqOfoQD+I8DarCU7YoKh/8+EJ27kCAwEAAaNjMGEwDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHwYDVR0jBBgwFoAUzC6tiYyD40CjJWml +6pJ90jc6x8YwHQYDVR0OBBYEFMwurYmMg+NAoyVppeqSfdI3OsfGMA0GCSqGSIb3 +DQEBCwUAA4ICAQAAB2YWpe3Hub+8yJGtWO1eEgWz9kabe+SEEC8HsVpeMm5tAPBe +x5piOYdN5Dzzvva6alNshG0H1GHKZ2a+mz5FMJ1R0tdaQq6dkg4jq9AVlD6omsqb +7cHCXyGjmYD8uaZhDlCAgCfH6H2g1JR6mAPn7kKL81JQXO++sHZaHAmhv4PAHnZl +0CVBW2mRk3f5jEvwLNubBgAXg/palLSGie+8CgsS+AZN0nPikThduWpLT6ev2iYl +kiMafB8nDZGE7xdy9kbrazs3qdTVmmO6XnmMKrWbojS1zJYn+XkIPH9t4P983MUm +r8OhemkW3Yc1c8ZrMWtWAS1PmdnuyuHQg962hecW+NGuM0j7Gs9dX4qEYXQHbxmw +USGyoQSxe1OP76JFrR+Y3flqBGyqNsWvjOopSUrn/1ezxjwRSRgX5maF4egj8osO +PJPEP3ZOfmKiKcsWMN4saa+Rp+JX5TNMv9iOB6J/oTVGaUqoICn/694glVmxrk0w +a9iatAMfwjjkINUO1howTGicjODtoQ+OQl3rgCoSeaYXF7SVKo40kae90ayoGkMh +i97v4KxGJWUKxiuhmz4i6Bg4tSb2LMoIIN4w0a1U/dxIFZ/Np0HXNziFME8SiEM0 +g9cqTdQAV1zlyvDd4ZIoKxh1vUekQhPpVlqNSl7ODnU1gHMZDywpi7uVuA== +-----END CERTIFICATE-----`)) + + // SwissSign RSA TLS Root CA 2022 - 1 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFkzCCA3ugAwIBAgIUQ/oMX04bgBhE79G0TzUfRPSA7cswDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzErMCkGA1UE +AxMiU3dpc3NTaWduIFJTQSBUTFMgUm9vdCBDQSAyMDIyIC0gMTAeFw0yMjA2MDgx +MTA4MjJaFw00NzA2MDgxMTA4MjJaMFExCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxT +d2lzc1NpZ24gQUcxKzApBgNVBAMTIlN3aXNzU2lnbiBSU0EgVExTIFJvb3QgQ0Eg +MjAyMiAtIDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLKmjiC8NX +vDVjvHClO/OMPE5Xlm7DTjak9gLKHqquuN6orx122ro10JFwB9+zBvKK8i5VUXu7 +LCTLf5ImgKO0lPaCoaTo+nUdWfMHamFk4saMla+ju45vVs9xzF6BYQ1t8qsCLqSX +5XH8irCRIFucdFJtrhUnWXjyCcplDn/L9Ovn3KlMd/YrFgSVrpxxpT8q2kFC5zyE +EPThPYxr4iuRR1VPuFa+Rd4iUU1OKNlfGUEGjw5NBuBwQCMBauTLE5tzrE0USJIt +/m2n+IdreXXhvhCxqohAWVTXz8TQm0SzOGlkjIHRI36qOTw7D59Ke4LKa2/KIj4x +0LDQKhySio/YGZxH5D4MucLNvkEM+KRHBdvBFzA4OmnczcNpI/2aDwLOEGrOyvi5 +KaM2iYauC8BPY7kGWUleDsFpswrzd34unYyzJ5jSmY0lpx+Gs6ZUcDj8fV3oT4MM +0ZPlEuRU2j7yrTrePjxF8CgPBrnh25d7mUWe3f6VWQQvdT/TromZhqwUtKiE+shd +OxtYk8EXlFXIC+OCeYSf8wCENO7cMdWP8vpPlkwGqnj73mSiI80fPsWMvDdUDrta +clXvyFu1cvh43zcgTFeRc5JzrBh3Q4IgaezprClG5QtO+DdziZaKHG29777YtvTK +wP1H8K4LWCDFyB02rpeNUIMmJCn3nTsPBQIDAQABo2MwYTAPBgNVHRMBAf8EBTAD +AQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBRvjmKLk0Ow4UD2p8P98Q+4 +DxU4pTAdBgNVHQ4EFgQUb45ii5NDsOFA9qfD/fEPuA8VOKUwDQYJKoZIhvcNAQEL +BQADggIBAKwsKUF9+lz1GpUYvyypiqkkVHX1uECry6gkUSsYP2OprphWKwVDIqO3 +10aewCoSPY6WlkDfDDOLazeROpW7OSltwAJsipQLBwJNGD77+3v1dj2b9l4wBlgz +Hqp41eZUBDqyggmNzhYzWUUo8aWjlw5DI/0LIICQ/+Mmz7hkkeUFjxOgdg3XNwwQ +iJb0Pr6VvfHDffCjw3lHC1ySFWPtUnWK50Zpy1FVCypM9fJkT6lc/2cyjlUtMoIc +gC9qkfjLvH4YoiaoLqNTKIftV+Vlek4ASltOU8liNr3CjlvrzG4ngRhZi0Rjn9UM +ZfQpZX+RLOV/fuiJz48gy20HQhFRJjKKLjpHE7iNvUcNCfAWpO2Whi4Z2L6MOuhF +LhG6rlrnub+xzI/goP+4s9GFe3lmozm1O2bYQL7Pt2eLSMkZJVX8vY3PXtpOpvJp +zv1/THfQwUY1mFwjmwJFQ5Ra3bxHrSL+ul4vkSkphnsh3m5kt8sNjzdbowhq6/Td +Ao9QAwKxuDdollDruF/UKIqlIgyKhPBZLtU30WHlQnNYKoH3dtvi4k0NX/a3vgW0 +rk4N3hY9A4GzJl5LuEsAz/+MF7psYC0nhzck5npgL7XTgwSqT0N1osGDsieYK7EO +gLrAhV5Cud+xYJHT6xh+cHiudoO+cVrQkOPKwRYlZ0rwtnu64ZzZ -----END CERTIFICATE-----`)) // TWCA CYBER Root CA @@ -4243,6 +4290,158 @@ vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE-----`)) + + // TrustAsia Global Root CA G3 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM +BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe +Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw +IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU +cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS +T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK +AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1 +nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep +qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA +yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs +hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX +zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv +kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT +f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA +uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB +o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih +MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E +BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4 +wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2 +XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1 +JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j +ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV +VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx +xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on +AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d +7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj +gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV ++Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo +FGWsJwt0ivKH +-----END CERTIFICATE-----`)) + + // TrustAsia Global Root CA G4 + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw +WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y +MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD +VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz +dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx +s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw +LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij +YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD +pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE +AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR +UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj +/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA== +-----END CERTIFICATE-----`)) + + // TrustAsia SMIME ECC Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICNjCCAbugAwIBAgIUWsL4KU/jfcVeHRhvO5MgH/97ui0wCgYIKoZIzj0EAwMw +WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xJDAiBgNVBAMTG1RydXN0QXNpYSBTTUlNRSBFQ0MgUm9vdCBDQTAeFw0y +NDA1MTUwNTQxNTlaFw00NDA1MTUwNTQxNThaMFoxCzAJBgNVBAYTAkNOMSUwIwYD +VQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDExtUcnVz +dEFzaWEgU01JTUUgRUNDIFJvb3QgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATN +2fsnvWnshsmQQ7FwF5SnyXcjOj8jZdMcox0eQlQg69BCu1m5i6zyho1Ljh2qliIj +OXZtkpvrIst6Q6Jz/XNLwiUPKrFpxv9F36k8lYC7qR5Kky/sHB2I9BGSN583mHKj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFDFn5nKyDeYioKzPfiKnWTLj +ZiOlMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNpADBmAjEA3TpMjaTGf+29 +pcZPPv0xSyjWilbfZRZ3h037ujIIgeCeM0iLn5SG7wErlOaM1tSOAjEAn4GcsCb9 +K9by9XGEnqjHiozWWBFStbgEy8xxdWPixhk42W1sGXGkFhkhk7oGRChs +-----END CERTIFICATE-----`)) + + // TrustAsia SMIME RSA Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFhDCCA2ygAwIBAgIUWu5x394MV4W1uzYi17h2RgJzyv8wDQYJKoZIhvcNAQEM +BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xJDAiBgNVBAMTG1RydXN0QXNpYSBTTUlNRSBSU0EgUm9vdCBDQTAe +Fw0yNDA1MTUwNTQyMDFaFw00NDA1MTUwNTQyMDBaMFoxCzAJBgNVBAYTAkNOMSUw +IwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDExtU +cnVzdEFzaWEgU01JTUUgUlNBIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCYlZytPFlz05N2pkhUphyIckxN4YL/GhMfUN6M2ZBC0byZ0zej +13E6yt1eG5BhQm6PQAFzfR8xutQdbgTSqpCESjMKRJ9aGR+0bi1o/K/An0oQEr8+ +gsKCsC/nkG+QZBCD7Ow2lAx8T+ACDT2HeUJNAOUwrnAfFf36z1IlNk15ILvxEJjg +YIfJ9XgMIu0C5hFs8ZtakRF0htD+eJKWBMOY78Zwr6mQqhb2Iu3Y+kYoceLJCMBQ +vHajui2W8hH5pL0QVvgnbStLZIjcF13PAAiKkq4azBLX3/AQKPPNOuo6Eowb52EJ +Q2rkOOn+dDnbzQo7w09T1q5x1TiDhx/O50zzEVWH37ev9+sahhBtqO1I3TLQ26oq +C3J3KXf9eug/eCAqaL7ebwjmtYVHgDf5cZaLpZhWl3wRZRaO1M7YJ9T5WsWnjbvR +Nw2lq2Vd2nSTiF7bdfZ/m8KasW0IAgyYSrvNMK92NQKFViNRCUAJBffwPR7CyHoa +usVBFbkNdrS0pLhF/Y2jOz0DKs2zlX80e92hT9k6/yf1DcIBnP9ZdVoayefS/X9P +D7X+DTzmoNb7tXZctDBNED/+4utaDrFPT1B+CDMCkVcySYmnQBBQF2ufY7qyslaY +dvT/cukEnNSnTE/2Oh9aVDFvy7oyrfhtr0XHe2NE38L9eOhKirB0dRbejwIDAQAB +o0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSAGqpDwcl/ixqWRbw9u2tI +UmxbqzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACp1gaGCIOp/ +Vq4JMJcQePTZQBRSpO5qf/AJKNYQY+BOe8kxxwilF+uvhuKXB0+pDqKFzO2kgIEd +WlMGPEwaqbeEhs989YUKcJnQ7TaRjed3Ls6EnCiGLSU1jEwB5n3bYV3id4TTAdFi +3QyiCmSk/PDtOkjyOew11qF6F3Hs09LsuCb7rRVwVkrPZMC5YFv35s2gwgMr+bLl +2rqlNxzYjdp5dCpn5KJ6xyyNpcFqgWzM9ak5aiJ9ouIIzemT27rLH3V3nveYrxTk +O6BMp3LntV5TScz/klfxWSsJuulSk8APRQth1mxZcwvY+QEv2gNPNxz034NeC0Gg +sXw5AKFs0Ni0kXIrGz+imtHE3yvVyJV9hM12G9zkJMY/FSI9hadCK+1+cVlhSMI9 +kWNAfCmzgBYKJfwYYA5TrQ4qzvxBOs2x5GprzDltyE1luKqTiHhuDwKL4JaOdB/Q +fuF0t/aBauQjrI79jzUdmnEKTypVL/4YwQD3e0iKZa9vCB1D51q4H6ToA+v9TLW0 +k6gx3kOdEr3n6aTS32/8b0aj7zFOjRerG6ng+Kk0VqEO53TsqIeF2Hc1S40+bnJ8 +SMwfcrNxdNQkhrzIwON5FAHO2fqBxlyz+V0MOL7O8o6NXz0l4VE5I6jqAI4Es79y +oMK6g/vNpJd1IJq/p1Di3a0sH/Q/o8gx +-----END CERTIFICATE-----`)) + + // TrustAsia TLS ECC Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIICMTCCAbegAwIBAgIUNnThTXxlE8msg1UloD5Sfi9QaMcwCgYIKoZIzj0EAwMw +WDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs +IEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgRUNDIFJvb3QgQ0EwHhcNMjQw +NTE1MDU0MTU2WhcNNDQwNTE1MDU0MTU1WjBYMQswCQYDVQQGEwJDTjElMCMGA1UE +ChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1c3RB +c2lhIFRMUyBFQ0MgUm9vdCBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLh/pVs/ +AT598IhtrimY4ZtcU5nb9wj/1WrgjstEpvDBjL1P1M7UiFPoXlfXTr4sP/MSpwDp +guMqWzJ8S5sUKZ74LYO1644xST0mYekdcouJtgq7nDM1D9rs3qlKH8kzsaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQULIVTu7FDzTLqnqOH/qKYqKaT6RAw +DgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMFRH18MtYYZI9HlaVQ01 +L18N9mdsd0AaRuf4aFtOJx24mH1/k78ITcTaRTChD15KeAIxAKORh/IRM4PDwYqR +OkwrULG9IpRdNYlzg8WbGf60oenUoWa2AaU2+dhoYSi3dOGiMQ== +-----END CERTIFICATE-----`)) + + // TrustAsia TLS RSA Root CA + mozillaIncluded.AppendCertsFromPEM([]byte(`-----BEGIN CERTIFICATE----- +MIIFgDCCA2igAwIBAgIUHBjYz+VTPyI1RlNUJDxsR9FcSpwwDQYJKoZIhvcNAQEM +BQAwWDELMAkGA1UEBhMCQ04xJTAjBgNVBAoTHFRydXN0QXNpYSBUZWNobm9sb2dp +ZXMsIEluYy4xIjAgBgNVBAMTGVRydXN0QXNpYSBUTFMgUlNBIFJvb3QgQ0EwHhcN +MjQwNTE1MDU0MTU3WhcNNDQwNTE1MDU0MTU2WjBYMQswCQYDVQQGEwJDTjElMCMG +A1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5jLjEiMCAGA1UEAxMZVHJ1 +c3RBc2lhIFRMUyBSU0EgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC +AgoCggIBAMMWuBtqpERz5dZO9LnPWwvB0ZqB9WOwj0PBuwhaGnrhB3YmH49pVr7+ +NmDQDIPNlOrnxS1cLwUWAp4KqC/lYCZUlviYQB2srp10Zy9U+5RjmOMmSoPGlbYJ +Q1DNDX3eRA5gEk9bNb2/mThtfWza4mhzH/kxpRkQcwUqwzIZheo0qt1CHjCNP561 +HmHVb70AcnKtEj+qpklz8oYVlQwQX1Fkzv93uMltrOXVmPGZLmzjyUT5tUMnCE32 +ft5EebuyjBza00tsLtbDeLdM1aTk2tyKjg7/D8OmYCYozza/+lcK7Fs/6TAWe8Tb +xNRkoDD75f0dcZLdKY9BWN4ArTr9PXwaqLEX8E40eFgl1oUh63kd0Nyrz2I8sMeX +i9bQn9P+PN7F4/w6g3CEIR0JwqH8uyghZVNgepBtljhb//HXeltt08lwSUq6HTrQ +UNoyIBnkiz/r1RYmNzz7dZ6wB3C4FGB33PYPXFIKvF1tjVEK2sUYyJtt3LCDs3+j +TnhMmCWr8n4uIF6CFabW2I+s5c0yhsj55NqJ4js+k8UTav/H9xj8Z7XvGCxUq0DT +bE3txci3OE9kxJRMT6DNrqXGJyV1J23G2pyOsAWZ1SgRxSHUuPzHlqtKZFlhaxP8 +S8ySpg+kUb8OWJDZgoM5pl+z+m6Ss80zDoWo8SnTq1mt1tve1CuBAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLgHkXlcBvRG/XtZylomkadFK/hT +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwFAAOCAgEAIZtqBSBdGBanEqT3 +Rz/NyjuujsCCztxIJXgXbODgcMTWltnZ9r96nBO7U5WS/8+S4PPFJzVXqDuiGev4 +iqME3mmL5Dw8veWv0BIb5Ylrc5tvJQJLkIKvQMKtuppgJFqBTQUYo+IzeXoLH5Pt +7DlK9RME7I10nYEKqG/odv6LTytpEoYKNDbdgptvT+Bz3Ul/KD7JO6NXBNiT2Twp +2xIQaOHEibgGIOcberyxk2GaGUARtWqFVwHxtlotJnMnlvm5P1vQiJ3koP26TpUJ +g3933FEFlJ0gcXax7PqJtZwuhfG5WyRasQmr2soaB82G39tp27RIGAAtvKLEiUUj +pQ7hRGU+isFqMB3iYPg6qocJQrmBktwliJiJ8Xw18WLK7nn4GS/+X/jbh87qqA8M +pugLoDzga5SYnH+tBuYc6kIQX+ImFTw3OffXvO645e8D7r0i+yiGNFjEWn9hongP +XvPKnbwbPKfILfanIhHKA9jnZwqKDss1jjQ52MjqjZ9k4DewbNfFj8GQYSbbJIwe +SsCI3zWQzj8C9GRh3sfIB5XeMhg6j6JCQCTl1jNdfK7vsU1P1FeQNWrcrgSXSYk0 +ly4wBOeY99sLAZDBHwo/+ML+TvrbmnNzFrwFuHnYWa8G5z9nODmxfKuU4CkUpijy +323imttUQ/hHWKNddBWcwauwxzQ= -----END CERTIFICATE-----`)) // Secure Global CA diff --git a/sing-box/common/certificate/store.go b/sing-box/common/certificate/store.go index 82ce8e29a5..cfced4630e 100644 --- a/sing-box/common/certificate/store.go +++ b/sing-box/common/certificate/store.go @@ -53,6 +53,8 @@ func NewStore(ctx context.Context, logger logger.Logger, options option.Certific } case C.CertificateStoreMozilla: systemPool = mozillaIncluded + case C.CertificateStoreChrome: + systemPool = chromeIncluded case C.CertificateStoreNone: systemPool = nil default: diff --git a/sing-box/common/tls/acme.go b/sing-box/common/tls/acme.go index 4a79c56c29..b8aef70fb0 100644 --- a/sing-box/common/tls/acme.go +++ b/sing-box/common/tls/acme.go @@ -114,13 +114,17 @@ func startACME(ctx context.Context, logger logger.Logger, options option.Inbound switch dnsOptions.Provider { case C.DNSProviderAliDNS: solver.DNSProvider = &alidns.Provider{ - AccKeyID: dnsOptions.AliDNSOptions.AccessKeyID, - AccKeySecret: dnsOptions.AliDNSOptions.AccessKeySecret, - RegionID: dnsOptions.AliDNSOptions.RegionID, + CredentialInfo: alidns.CredentialInfo{ + AccessKeyID: dnsOptions.AliDNSOptions.AccessKeyID, + AccessKeySecret: dnsOptions.AliDNSOptions.AccessKeySecret, + RegionID: dnsOptions.AliDNSOptions.RegionID, + SecurityToken: dnsOptions.AliDNSOptions.SecurityToken, + }, } case C.DNSProviderCloudflare: solver.DNSProvider = &cloudflare.Provider{ - APIToken: dnsOptions.CloudflareOptions.APIToken, + APIToken: dnsOptions.CloudflareOptions.APIToken, + ZoneToken: dnsOptions.CloudflareOptions.ZoneToken, } default: return nil, nil, E.New("unsupported ACME DNS01 provider type: " + dnsOptions.Provider) diff --git a/sing-box/constant/certificate.go b/sing-box/constant/certificate.go index 7138242ce9..05ab161687 100644 --- a/sing-box/constant/certificate.go +++ b/sing-box/constant/certificate.go @@ -3,5 +3,6 @@ package constant const ( CertificateStoreSystem = "system" CertificateStoreMozilla = "mozilla" + CertificateStoreChrome = "chrome" CertificateStoreNone = "none" ) diff --git a/sing-box/dns/client.go b/sing-box/dns/client.go index 8db45d4121..939ca48cbf 100644 --- a/sing-box/dns/client.go +++ b/sing-box/dns/client.go @@ -353,68 +353,6 @@ func (c *Client) ClearCache() { } } -func (c *Client) LookupCache(domain string, strategy C.DomainStrategy) ([]netip.Addr, bool) { - if c.disableCache || c.independentCache { - return nil, false - } - if dns.IsFqdn(domain) { - domain = domain[:len(domain)-1] - } - dnsName := dns.Fqdn(domain) - if strategy == C.DomainStrategyIPv4Only { - addresses, err := c.questionCache(dns.Question{ - Name: dnsName, - Qtype: dns.TypeA, - Qclass: dns.ClassINET, - }, nil) - if err != ErrNotCached { - return addresses, true - } - } else if strategy == C.DomainStrategyIPv6Only { - addresses, err := c.questionCache(dns.Question{ - Name: dnsName, - Qtype: dns.TypeAAAA, - Qclass: dns.ClassINET, - }, nil) - if err != ErrNotCached { - return addresses, true - } - } else { - response4, _ := c.loadResponse(dns.Question{ - Name: dnsName, - Qtype: dns.TypeA, - Qclass: dns.ClassINET, - }, nil) - if response4 == nil { - return nil, false - } - response6, _ := c.loadResponse(dns.Question{ - Name: dnsName, - Qtype: dns.TypeAAAA, - Qclass: dns.ClassINET, - }, nil) - if response6 == nil { - return nil, false - } - return sortAddresses(MessageToAddresses(response4), MessageToAddresses(response6), strategy), true - } - return nil, false -} - -func (c *Client) ExchangeCache(ctx context.Context, message *dns.Msg) (*dns.Msg, bool) { - if c.disableCache || c.independentCache || len(message.Question) != 1 { - return nil, false - } - question := message.Question[0] - response, ttl := c.loadResponse(question, nil) - if response == nil { - return nil, false - } - logCachedResponse(c.logger, ctx, response, ttl) - response.Id = message.Id - return response, true -} - func sortAddresses(response4 []netip.Addr, response6 []netip.Addr, strategy C.DomainStrategy) []netip.Addr { if strategy == C.DomainStrategyPreferIPv6 { return append(response6, response4...) diff --git a/sing-box/dns/router.go b/sing-box/dns/router.go index 2a9d2f9714..1038fdf08c 100644 --- a/sing-box/dns/router.go +++ b/sing-box/dns/router.go @@ -213,97 +213,95 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapte } r.logger.DebugContext(ctx, "exchange ", FormatQuestion(message.Question[0].String())) var ( + response *mDNS.Msg transport adapter.DNSTransport err error ) - response, cached := r.client.ExchangeCache(ctx, message) - if !cached { - var metadata *adapter.InboundContext - ctx, metadata = adapter.ExtendContext(ctx) - metadata.Destination = M.Socksaddr{} - metadata.QueryType = message.Question[0].Qtype - switch metadata.QueryType { - case mDNS.TypeA: - metadata.IPVersion = 4 - case mDNS.TypeAAAA: - metadata.IPVersion = 6 - } - metadata.Domain = FqdnToDomain(message.Question[0].Name) - if options.Transport != nil { - transport = options.Transport - if legacyTransport, isLegacy := transport.(adapter.LegacyDNSTransport); isLegacy { - if options.Strategy == C.DomainStrategyAsIS { - options.Strategy = legacyTransport.LegacyStrategy() - } - if !options.ClientSubnet.IsValid() { - options.ClientSubnet = legacyTransport.LegacyClientSubnet() - } - } + var metadata *adapter.InboundContext + ctx, metadata = adapter.ExtendContext(ctx) + metadata.Destination = M.Socksaddr{} + metadata.QueryType = message.Question[0].Qtype + switch metadata.QueryType { + case mDNS.TypeA: + metadata.IPVersion = 4 + case mDNS.TypeAAAA: + metadata.IPVersion = 6 + } + metadata.Domain = FqdnToDomain(message.Question[0].Name) + if options.Transport != nil { + transport = options.Transport + if legacyTransport, isLegacy := transport.(adapter.LegacyDNSTransport); isLegacy { if options.Strategy == C.DomainStrategyAsIS { - options.Strategy = r.defaultDomainStrategy + options.Strategy = legacyTransport.LegacyStrategy() } - response, err = r.client.Exchange(ctx, transport, message, options, nil) - } else { - var ( - rule adapter.DNSRule - ruleIndex int - ) - ruleIndex = -1 - for { - dnsCtx := adapter.OverrideContext(ctx) - dnsOptions := options - transport, rule, ruleIndex = r.matchDNS(ctx, true, ruleIndex, isAddressQuery(message), &dnsOptions) - if rule != nil { - switch action := rule.Action().(type) { - case *R.RuleActionReject: - switch action.Method { - case C.RuleActionRejectMethodDefault: - return &mDNS.Msg{ - MsgHdr: mDNS.MsgHdr{ - Id: message.Id, - Rcode: mDNS.RcodeRefused, - Response: true, - }, - Question: []mDNS.Question{message.Question[0]}, - }, nil - case C.RuleActionRejectMethodDrop: - return nil, tun.ErrDrop - } - case *R.RuleActionPredefined: - return action.Response(message), nil - } - } - var responseCheck func(responseAddrs []netip.Addr) bool - if rule != nil && rule.WithAddressLimit() { - responseCheck = func(responseAddrs []netip.Addr) bool { - metadata.DestinationAddresses = responseAddrs - return rule.MatchAddressLimit(metadata) - } - } - if dnsOptions.Strategy == C.DomainStrategyAsIS { - dnsOptions.Strategy = r.defaultDomainStrategy - } - response, err = r.client.Exchange(dnsCtx, transport, message, dnsOptions, responseCheck) - var rejected bool - if err != nil { - if errors.Is(err, ErrResponseRejectedCached) { - rejected = true - r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())), " (cached)") - } else if errors.Is(err, ErrResponseRejected) { - rejected = true - r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String()))) - } else if len(message.Question) > 0 { - r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", FormatQuestion(message.Question[0].String()))) - } else { - r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ")) - } - } - if responseCheck != nil && rejected { - continue - } - break + if !options.ClientSubnet.IsValid() { + options.ClientSubnet = legacyTransport.LegacyClientSubnet() } } + if options.Strategy == C.DomainStrategyAsIS { + options.Strategy = r.defaultDomainStrategy + } + response, err = r.client.Exchange(ctx, transport, message, options, nil) + } else { + var ( + rule adapter.DNSRule + ruleIndex int + ) + ruleIndex = -1 + for { + dnsCtx := adapter.OverrideContext(ctx) + dnsOptions := options + transport, rule, ruleIndex = r.matchDNS(ctx, true, ruleIndex, isAddressQuery(message), &dnsOptions) + if rule != nil { + switch action := rule.Action().(type) { + case *R.RuleActionReject: + switch action.Method { + case C.RuleActionRejectMethodDefault: + return &mDNS.Msg{ + MsgHdr: mDNS.MsgHdr{ + Id: message.Id, + Rcode: mDNS.RcodeRefused, + Response: true, + }, + Question: []mDNS.Question{message.Question[0]}, + }, nil + case C.RuleActionRejectMethodDrop: + return nil, tun.ErrDrop + } + case *R.RuleActionPredefined: + return action.Response(message), nil + } + } + var responseCheck func(responseAddrs []netip.Addr) bool + if rule != nil && rule.WithAddressLimit() { + responseCheck = func(responseAddrs []netip.Addr) bool { + metadata.DestinationAddresses = responseAddrs + return rule.MatchAddressLimit(metadata) + } + } + if dnsOptions.Strategy == C.DomainStrategyAsIS { + dnsOptions.Strategy = r.defaultDomainStrategy + } + response, err = r.client.Exchange(dnsCtx, transport, message, dnsOptions, responseCheck) + var rejected bool + if err != nil { + if errors.Is(err, ErrResponseRejectedCached) { + rejected = true + r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String())), " (cached)") + } else if errors.Is(err, ErrResponseRejected) { + rejected = true + r.logger.DebugContext(ctx, E.Cause(err, "response rejected for ", FormatQuestion(message.Question[0].String()))) + } else if len(message.Question) > 0 { + r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ", FormatQuestion(message.Question[0].String()))) + } else { + r.logger.ErrorContext(ctx, E.Cause(err, "exchange failed for ")) + } + } + if responseCheck != nil && rejected { + continue + } + break + } } if err != nil { return nil, err @@ -326,7 +324,6 @@ func (r *Router) Exchange(ctx context.Context, message *mDNS.Msg, options adapte func (r *Router) Lookup(ctx context.Context, domain string, options adapter.DNSQueryOptions) ([]netip.Addr, error) { var ( responseAddrs []netip.Addr - cached bool err error ) printResult := func() { @@ -346,13 +343,6 @@ func (r *Router) Lookup(ctx context.Context, domain string, options adapter.DNSQ err = E.Cause(err, "lookup ", domain) } } - responseAddrs, cached = r.client.LookupCache(domain, options.Strategy) - if cached { - if len(responseAddrs) == 0 { - return nil, E.New("lookup ", domain, ": empty result (cached)") - } - return responseAddrs, nil - } r.logger.DebugContext(ctx, "lookup domain ", domain) ctx, metadata := adapter.ExtendContext(ctx) metadata.Destination = M.Socksaddr{} diff --git a/sing-box/docs/configuration/certificate/index.md b/sing-box/docs/configuration/certificate/index.md index 698fec70eb..88d733802d 100644 --- a/sing-box/docs/configuration/certificate/index.md +++ b/sing-box/docs/configuration/certificate/index.md @@ -4,6 +4,10 @@ icon: material/new-box !!! question "Since sing-box 1.12.0" +!!! quote "Changes in sing-box 1.13.0" + + :material-plus: [Chrome Root Store](#store) + # Certificate ### Structure @@ -27,11 +31,12 @@ icon: material/new-box The default X509 trusted CA certificate list. -| Type | Description | -|--------------------|---------------------------------------------------------------------------------------------------------------| -| `system` (default) | System trusted CA certificates | +| Type | Description | +|--------------------|----------------------------------------------------------------------------------------------------------------| +| `system` (default) | System trusted CA certificates | | `mozilla` | [Mozilla Included List](https://wiki.mozilla.org/CA/Included_Certificates) with China CA certificates removed | -| `none` | Empty list | +| `chrome` | [Chrome Root Store](https://g.co/chrome/root-policy) with China CA certificates removed | +| `none` | Empty list | #### certificate diff --git a/sing-box/docs/configuration/certificate/index.zh.md b/sing-box/docs/configuration/certificate/index.zh.md index 9572e9cd38..77f3fd88b4 100644 --- a/sing-box/docs/configuration/certificate/index.zh.md +++ b/sing-box/docs/configuration/certificate/index.zh.md @@ -4,6 +4,10 @@ icon: material/new-box !!! question "自 sing-box 1.12.0 起" +!!! quote "sing-box 1.13.0 中的更改" + + :material-plus: [Chrome Root Store](#store) + # 证书 ### 结构 @@ -27,11 +31,12 @@ icon: material/new-box 默认的 X509 受信任 CA 证书列表。 -| 类型 | 描述 | -|--------------------|--------------------------------------------------------------------------------------------| -| `system`(默认) | 系统受信任的 CA 证书 | -| `mozilla` | [Mozilla 包含列表](https://wiki.mozilla.org/CA/Included_Certificates)(已移除中国 CA 证书) | -| `none` | 空列表 | +| 类型 | 描述 | +|-------------------|--------------------------------------------------------------------------------------------| +| `system`(默认) | 系统受信任的 CA 证书 | +| `mozilla` | [Mozilla 包含列表](https://wiki.mozilla.org/CA/Included_Certificates)(已移除中国 CA 证书) | +| `chrome` | [Chrome Root Store](https://g.co/chrome/root-policy)(已移除中国 CA 证书) | +| `none` | 空列表 | #### certificate diff --git a/sing-box/docs/configuration/shared/dns01_challenge.md b/sing-box/docs/configuration/shared/dns01_challenge.md index f9949e169b..23265bd64e 100644 --- a/sing-box/docs/configuration/shared/dns01_challenge.md +++ b/sing-box/docs/configuration/shared/dns01_challenge.md @@ -1,9 +1,18 @@ +--- +icon: material/new-box +--- + +!!! quote "Changes in sing-box 1.13.0" + + :material-plus: [alidns.security_token](#security_token) + :material-plus: [cloudflare.zone_token](#zone_token) + ### Structure ```json { "provider": "", - + ... // Provider Fields } ``` @@ -17,15 +26,31 @@ "provider": "alidns", "access_key_id": "", "access_key_secret": "", - "region_id": "" + "region_id": "", + "security_token": "" } ``` +##### security_token + +!!! question "Since sing-box 1.13.0" + +The Security Token for STS temporary credentials. + #### Cloudflare ```json { "provider": "cloudflare", - "api_token": "" + "api_token": "", + "zone_token": "" } -``` \ No newline at end of file +``` + +##### zone_token + +!!! question "Since sing-box 1.13.0" + +Optional API token with `Zone:Read` permission. + +When provided, allows `api_token` to be scoped to a single zone. diff --git a/sing-box/docs/configuration/shared/dns01_challenge.zh.md b/sing-box/docs/configuration/shared/dns01_challenge.zh.md index c942fef0f1..c316a9fd30 100644 --- a/sing-box/docs/configuration/shared/dns01_challenge.zh.md +++ b/sing-box/docs/configuration/shared/dns01_challenge.zh.md @@ -1,9 +1,18 @@ +--- +icon: material/new-box +--- + +!!! quote "sing-box 1.13.0 中的更改" + + :material-plus: [alidns.security_token](#security_token) + :material-plus: [cloudflare.zone_token](#zone_token) + ### 结构 ```json { "provider": "", - + ... // 提供商字段 } ``` @@ -17,15 +26,31 @@ "provider": "alidns", "access_key_id": "", "access_key_secret": "", - "region_id": "" + "region_id": "", + "security_token": "" } ``` +##### security_token + +!!! question "自 sing-box 1.13.0 起" + +用于 STS 临时凭证的安全令牌。 + #### Cloudflare ```json { "provider": "cloudflare", - "api_token": "" + "api_token": "", + "zone_token": "" } -``` \ No newline at end of file +``` + +##### zone_token + +!!! question "自 sing-box 1.13.0 起" + +具有 `Zone:Read` 权限的可选 API 令牌。 + +提供后可将 `api_token` 限定到单个区域。 diff --git a/sing-box/go.mod b/sing-box/go.mod index b7d83f57f4..d1cbf8271e 100644 --- a/sing-box/go.mod +++ b/sing-box/go.mod @@ -3,25 +3,25 @@ module github.com/sagernet/sing-box go 1.24.7 require ( - github.com/anthropics/anthropic-sdk-go v1.14.0 + github.com/anthropics/anthropic-sdk-go v1.19.0 github.com/anytls/sing-anytls v0.0.11 - github.com/caddyserver/certmagic v0.23.0 - github.com/coder/websocket v1.8.13 + github.com/caddyserver/certmagic v0.25.0 + github.com/coder/websocket v1.8.14 github.com/cretz/bine v0.2.0 github.com/database64128/tfo-go/v2 v2.3.1 - github.com/go-chi/chi/v5 v5.2.2 + github.com/go-chi/chi/v5 v5.2.3 github.com/go-chi/render v1.0.3 - github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 - github.com/gofrs/uuid/v5 v5.3.2 - github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f + github.com/godbus/dbus/v5 v5.2.1 + github.com/gofrs/uuid/v5 v5.4.0 + github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167 github.com/keybase/go-keychain v0.0.1 - github.com/libdns/alidns v1.0.5-libdns.v1.beta1 - github.com/libdns/cloudflare v0.2.2-0.20250708034226-c574dccb31a6 + github.com/libdns/alidns v1.0.6-beta.3 + github.com/libdns/cloudflare v0.2.2 github.com/logrusorgru/aurora v2.0.3+incompatible github.com/metacubex/utls v1.8.3 - github.com/mholt/acmez/v3 v3.1.2 - github.com/miekg/dns v1.1.67 - github.com/openai/openai-go/v3 v3.13.0 + github.com/mholt/acmez/v3 v3.1.4 + github.com/miekg/dns v1.1.69 + github.com/openai/openai-go/v3 v3.15.0 github.com/oschwald/maxminddb-golang v1.13.1 github.com/sagernet/asc-go v0.0.0-20241217030726-d563060fe4e1 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a @@ -31,10 +31,10 @@ require ( github.com/sagernet/fswatch v0.1.1 github.com/sagernet/gomobile v0.1.10 github.com/sagernet/gvisor v0.0.0-20250811.0-sing-box-mod.1 - github.com/sagernet/quic-go v0.57.1-sing-box-mod.3 + github.com/sagernet/quic-go v0.58.0-sing-box-mod.1 github.com/sagernet/sing v0.8.0-beta.6.0.20251207063731-56fd482ce1c6 github.com/sagernet/sing-mux v0.3.3 - github.com/sagernet/sing-quic v0.6.0-beta.5.0.20251218085114-6968f531a8c0 + github.com/sagernet/sing-quic v0.6.0-beta.6 github.com/sagernet/sing-shadowsocks v0.2.8 github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 @@ -44,19 +44,19 @@ require ( github.com/sagernet/tailscale v1.86.5-sing-box-1.13-mod.4 github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 - github.com/spf13/cobra v1.9.1 + github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 github.com/vishvananda/netns v0.0.5 - go.uber.org/zap v1.27.0 + go.uber.org/zap v1.27.1 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - golang.org/x/crypto v0.42.0 - golang.org/x/exp v0.0.0-20250911091902-df9299821621 - golang.org/x/mod v0.28.0 - golang.org/x/net v0.44.0 - golang.org/x/sys v0.36.0 + golang.org/x/crypto v0.46.0 + golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 + golang.org/x/mod v0.31.0 + golang.org/x/net v0.48.0 + golang.org/x/sys v0.39.0 golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 - google.golang.org/grpc v1.73.0 - google.golang.org/protobuf v1.36.6 + google.golang.org/grpc v1.77.0 + google.golang.org/protobuf v1.36.11 howett.net/plist v1.0.1 ) @@ -96,8 +96,8 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jsimonetti/rtnetlink v1.4.0 // indirect github.com/klauspost/compress v1.17.11 // indirect - github.com/klauspost/cpuid/v2 v2.2.10 // indirect - github.com/libdns/libdns v1.1.0 // indirect + github.com/klauspost/cpuid/v2 v2.3.0 // indirect + github.com/libdns/libdns v1.1.1 // indirect github.com/mdlayher/genetlink v1.3.2 // indirect github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect github.com/mdlayher/sdnotify v1.0.0 // indirect @@ -132,7 +132,7 @@ require ( github.com/sagernet/cronet-go/lib/windows_arm64 v0.0.0-20251220122226-25b6d00c5b7e // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/spf13/pflag v1.0.9 // indirect github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e // indirect github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 // indirect github.com/tailscale/goupnp v1.0.1-0.20210804011211-c64d0f06ea05 // indirect @@ -151,14 +151,14 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect go4.org/mem v0.0.0-20240501181205-ae6ca9944745 // indirect - golang.org/x/sync v0.17.0 // indirect - golang.org/x/term v0.35.0 // indirect - golang.org/x/text v0.29.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.37.0 // indirect + golang.org/x/tools v0.40.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect golang.zx2c4.com/wireguard/windows v0.5.3 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect ) diff --git a/sing-box/go.sum b/sing-box/go.sum index f823efef3d..5bf4057684 100644 --- a/sing-box/go.sum +++ b/sing-box/go.sum @@ -8,20 +8,20 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7V github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/anthropics/anthropic-sdk-go v1.14.0 h1:EzNQvnZlaDHe2UPkoUySDz3ixRgNbwKdH8KtFpv7pi4= -github.com/anthropics/anthropic-sdk-go v1.14.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE= +github.com/anthropics/anthropic-sdk-go v1.19.0 h1:mO6E+ffSzLRvR/YUH9KJC0uGw0uV8GjISIuzem//3KE= +github.com/anthropics/anthropic-sdk-go v1.19.0/go.mod h1:WTz31rIUHUHqai2UslPpw5CwXrQP3geYBioRV4WOLvE= github.com/anytls/sing-anytls v0.0.11 h1:w8e9Uj1oP3m4zxkyZDewPk0EcQbvVxb7Nn+rapEx4fc= github.com/anytls/sing-anytls v0.0.11/go.mod h1:7rjN6IukwysmdusYsrV51Fgu1uW6vsrdd6ctjnEAln8= -github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU= -github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4= +github.com/caddyserver/certmagic v0.25.0 h1:VMleO/XA48gEWes5l+Fh6tRWo9bHkhwAEhx63i+F5ic= +github.com/caddyserver/certmagic v0.25.0/go.mod h1:m9yB7Mud24OQbPHOiipAoyKPn9pKHhpSJxXR1jydBxA= github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk= github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso= -github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE= -github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs= +github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= +github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0= github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -51,14 +51,14 @@ github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= -github.com/go-chi/chi/v5 v5.2.2 h1:CMwsvRVTbXVytCk1Wd72Zy1LAsAh9GxMmSNWLHCG618= -github.com/go-chi/chi/v5 v5.2.2/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= +github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= +github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874 h1:F8d1AJ6M9UQCavhwmO6ZsrYLfG8zVFWfEfMS2MXPkSY= github.com/go-json-experiment/json v0.0.0-20250223041408-d3c622f1b874/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= @@ -67,10 +67,10 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466 h1:sQspH8M4niEijh3PFscJRLDnkL547IeP7kpPe3uUhEg= -github.com/godbus/dbus/v5 v5.1.1-0.20230522191255-76236955d466/go.mod h1:ZiQxhyQ+bbbfxUKVvjfO498oPYvtYhZzycal3G/NHmU= -github.com/gofrs/uuid/v5 v5.3.2 h1:2jfO8j3XgSwlz/wHqemAEugfnTlikAYHhnqQ8Xh4fE0= -github.com/gofrs/uuid/v5 v5.3.2/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/godbus/dbus/v5 v5.2.1 h1:I4wwMdWSkmI57ewd+elNGwLRf2/dtSaFz1DujfWYvOk= +github.com/godbus/dbus/v5 v5.2.1/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0= +github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -94,8 +94,8 @@ github.com/illarion/gonotify/v3 v3.0.2 h1:O7S6vcopHexutmpObkeWsnzMJt/r1hONIEogeV github.com/illarion/gonotify/v3 v3.0.2/go.mod h1:HWGPdPe817GfvY3w7cx6zkbzNZfi3QjcBm/wgVvEL1U= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f h1:dd33oobuIv9PcBVqvbEiCXEbNTomOHyj3WFuC5YiPRU= -github.com/insomniacslk/dhcp v0.0.0-20250417080101-5f8cf70e8c5f/go.mod h1:zhFlBeJssZ1YBCMZ5Lzu1pX4vhftDvU10WUVb1uXKtM= +github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167 h1:MEufgJohwIjFi2n3eJv4c/8UdRLQVUwPwSWQPoER+eU= +github.com/insomniacslk/dhcp v0.0.0-20251020182700-175e84fbb167/go.mod h1:qfvBmyDNp+/liLEYWRvqny/PEz9hGe2Dz833eXILSmo= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jsimonetti/rtnetlink v1.4.0 h1:Z1BF0fRgcETPEa0Kt0MRk3yV5+kF1FWTni6KUFKrq2I= github.com/jsimonetti/rtnetlink v1.4.0/go.mod h1:5W1jDvWdnthFJ7fxYX1GMK07BUpI4oskfOqvPteYS6E= @@ -103,15 +103,14 @@ github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRt github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= -github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= -github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= -github.com/libdns/alidns v1.0.5-libdns.v1.beta1 h1:txHK7UxDed3WFBDjrTZPuMn8X+WmhjBTTAMW5xdy5pQ= -github.com/libdns/alidns v1.0.5-libdns.v1.beta1/go.mod h1:ystHmPwcGoWjPrGpensQSMY9VoCx4cpR2hXNlwk9H/g= -github.com/libdns/cloudflare v0.2.2-0.20250708034226-c574dccb31a6 h1:3MGrVWs2COjMkQR17oUw1zMIPbm2YAzxDC3oGVZvQs8= -github.com/libdns/cloudflare v0.2.2-0.20250708034226-c574dccb31a6/go.mod h1:w9uTmRCDlAoafAsTPnn2nJ0XHK/eaUMh86DUk8BWi60= -github.com/libdns/libdns v1.0.0-beta.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= -github.com/libdns/libdns v1.1.0 h1:9ze/tWvt7Df6sbhOJRB8jT33GHEHpEQXdtkE3hPthbU= -github.com/libdns/libdns v1.1.0/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/libdns/alidns v1.0.6-beta.3 h1:KAmb7FQ1tRzKsaAUGa7ZpGKAMRANwg7+1c7tUbSELq8= +github.com/libdns/alidns v1.0.6-beta.3/go.mod h1:RECwyQ88e9VqQVtSrvX76o1ux3gQUKGzMgxICi+u7Ec= +github.com/libdns/cloudflare v0.2.2 h1:XWHv+C1dDcApqazlh08Q6pjytYLgR2a+Y3xrXFu0vsI= +github.com/libdns/cloudflare v0.2.2/go.mod h1:w9uTmRCDlAoafAsTPnn2nJ0XHK/eaUMh86DUk8BWi60= +github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U= +github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw= @@ -124,16 +123,16 @@ github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4= github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= -github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc= -github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= -github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0= -github.com/miekg/dns v1.1.67/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= +github.com/mholt/acmez/v3 v3.1.4 h1:DyzZe/RnAzT3rpZj/2Ii5xZpiEvvYk3cQEN/RmqxwFQ= +github.com/mholt/acmez/v3 v3.1.4/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= +github.com/miekg/dns v1.1.69 h1:Kb7Y/1Jo+SG+a2GtfoFUfDkG//csdRPwRLkCsxDG9Sc= +github.com/miekg/dns v1.1.69/go.mod h1:7OyjD9nEba5OkqQ/hB4fy3PIoxafSZJtducccIelz3g= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/openai/openai-go/v3 v3.13.0 h1:arSFmVHcBHNVYG5iqspPJrLoin0Qqn2JcCLWWcTcM1Q= -github.com/openai/openai-go/v3 v3.13.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo= +github.com/openai/openai-go/v3 v3.15.0 h1:hk99rM7YPz+M99/5B/zOQcVwFRLLMdprVGx1vaZ8XMo= +github.com/openai/openai-go/v3 v3.15.0/go.mod h1:cdufnVK14cWcT9qA1rRtrXx4FTRsgbDPW7Ia7SS5cZo= github.com/oschwald/maxminddb-golang v1.13.1 h1:G3wwjdN9JmIK2o/ermkHM+98oX5fS+k5MbwsmL4MRQE= github.com/oschwald/maxminddb-golang v1.13.1/go.mod h1:K4pgV9N/GcK694KSTmVSDTODk4IsCNThNdTmnaBZ/F8= github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ= @@ -212,15 +211,15 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= -github.com/sagernet/quic-go v0.57.1-sing-box-mod.3 h1:Rah/tDukrowqlznHQgXD4E9/yEsVsEMIxBZzS2NorGc= -github.com/sagernet/quic-go v0.57.1-sing-box-mod.3/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= +github.com/sagernet/quic-go v0.58.0-sing-box-mod.1 h1:E9yZrU0ZxSiW5RrGUnFZeI02EIMdAAv0RxdoxXCqZyk= +github.com/sagernet/quic-go v0.58.0-sing-box-mod.1/go.mod h1:OqILvS182CyOol5zNNo6bguvOGgXzV459+chpRaUC+4= github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing v0.8.0-beta.6.0.20251207063731-56fd482ce1c6 h1:EYaDzllFzNYnzQ9xH/ieSAXct4wQ8pD45kgNMo7RPZc= github.com/sagernet/sing v0.8.0-beta.6.0.20251207063731-56fd482ce1c6/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw= github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA= -github.com/sagernet/sing-quic v0.6.0-beta.5.0.20251218085114-6968f531a8c0 h1:YNXy008FFkVwfNjCR8GlVTlHbBXPwv8Y4ytDnSFUSDo= -github.com/sagernet/sing-quic v0.6.0-beta.5.0.20251218085114-6968f531a8c0/go.mod h1:Y3YVjPutLHLQvYjGtUFH+w8YmM4MTd19NDzxLZGNGIs= +github.com/sagernet/sing-quic v0.6.0-beta.6 h1:aqunNgNABqfSYI9V6NEHyXNVLPPkFQI0kADqjuKQOzA= +github.com/sagernet/sing-quic v0.6.0-beta.6/go.mod h1:0NodMFjlAvfLp87Enpx46fQPrGRvmbUsmy5hRLzomtM= github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE= github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI= github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo= @@ -239,10 +238,10 @@ github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288 h1: github.com/sagernet/wireguard-go v0.0.2-beta.1.0.20250917110311-16510ac47288/go.mod h1:WUxgxUDZoCF2sxVmW+STSxatP02Qn3FcafTiI2BLtE0= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= +github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= +github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -295,68 +294,68 @@ github.com/zeebo/blake3 v0.2.4 h1:KYQPkhpRtcqh0ssGYcKLG1JYvddkEA8QwCM/yBqhaZI= github.com/zeebo/blake3 v0.2.4/go.mod h1:7eeQ6d2iXWRGF6npfaxl2CU+xy2Fjo2gxeyZGCRUjcE= github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo= github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go4.org/mem v0.0.0-20240501181205-ae6ca9944745 h1:Tl++JLUCe4sxGu8cTpDzRLd3tN7US4hOxG5YpKCzkek= go4.org/mem v0.0.0-20240501181205-ae6ca9944745/go.mod h1:reUoABIJ9ikfM5sgtSF3Wushcza7+WeD01VB9Lirh3g= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI= -golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8= -golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU= -golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w= golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g= -golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U= -golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI= +golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI= +golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= -golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= -golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20220817070843-5a390386f1f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ= -golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= -golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE= -golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -366,12 +365,14 @@ golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdI golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ= golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus8eIuExIE= golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= +google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= diff --git a/sing-box/option/tls_acme.go b/sing-box/option/tls_acme.go index 502706073d..1857c747bc 100644 --- a/sing-box/option/tls_acme.go +++ b/sing-box/option/tls_acme.go @@ -75,8 +75,10 @@ type ACMEDNS01AliDNSOptions struct { AccessKeyID string `json:"access_key_id,omitempty"` AccessKeySecret string `json:"access_key_secret,omitempty"` RegionID string `json:"region_id,omitempty"` + SecurityToken string `json:"security_token,omitempty"` } type ACMEDNS01CloudflareOptions struct { - APIToken string `json:"api_token,omitempty"` + APIToken string `json:"api_token,omitempty"` + ZoneToken string `json:"zone_token,omitempty"` } diff --git a/sing-box/protocol/naive/quic/inbound_init.go b/sing-box/protocol/naive/quic/inbound_init.go index 956132acd5..feb63441a6 100644 --- a/sing-box/protocol/naive/quic/inbound_init.go +++ b/sing-box/protocol/naive/quic/inbound_init.go @@ -10,6 +10,7 @@ import ( "github.com/sagernet/quic-go/http3" "github.com/sagernet/sing-box/common/listener" "github.com/sagernet/sing-box/common/tls" + "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/protocol/naive" "github.com/sagernet/sing-quic" @@ -92,9 +93,8 @@ func init() { } quicListener, err := qtls.ListenEarly(udpConn, tlsConfig, &quic.Config{ - MaxIncomingStreams: 1 << 60, - Allow0RTT: true, - GetCongestionControl: congestionControl, + MaxIncomingStreams: 1 << 60, + Allow0RTT: true, }) if err != nil { udpConn.Close() @@ -103,6 +103,10 @@ func init() { h3Server := &http3.Server{ Handler: handler, + ConnContext: func(ctx context.Context, conn *quic.Conn) context.Context { + conn.SetCongestionControl(congestionControl(conn)) + return log.ContextWithNewID(ctx) + }, } go func() { diff --git a/small/gn/Makefile b/small/gn/Makefile index 78c42f9315..5263ebdfd3 100644 --- a/small/gn/Makefile +++ b/small/gn/Makefile @@ -9,9 +9,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://gn.googlesource.com/gn.git -PKG_SOURCE_DATE:=2025-12-14 -PKG_SOURCE_VERSION:=4e0818fd86bffc0b4a4b61d3295a6732ba08d715 -PKG_MIRROR_HASH:=0369c35da5a7a1ce5a068d3c44535d51ce237dacabae3f0827f3e8a476a03e92 +PKG_SOURCE_DATE:=2025-12-21 +PKG_SOURCE_VERSION:=64d35867ca0a1088f13de8f4ccaf1a5687d7f1ce +PKG_MIRROR_HASH:=0fc81f9f57c89030264fdf8d65f3473e8c353f4e6a9096226a4a818ad4fbdf8e PKG_LICENSE:=BSD 3-Clause PKG_LICENSE_FILES:=LICENSE diff --git a/small/gn/src/out/last_commit_position.h b/small/gn/src/out/last_commit_position.h index eb3dc12de8..6d1453308a 100644 --- a/small/gn/src/out/last_commit_position.h +++ b/small/gn/src/out/last_commit_position.h @@ -3,7 +3,7 @@ #ifndef OUT_LAST_COMMIT_POSITION_H_ #define OUT_LAST_COMMIT_POSITION_H_ -#define LAST_COMMIT_POSITION_NUM 2310 -#define LAST_COMMIT_POSITION "2310 (4e0818fd86bf)" +#define LAST_COMMIT_POSITION_NUM 2312 +#define LAST_COMMIT_POSITION "2312 (64d35867ca0a)" #endif // OUT_LAST_COMMIT_POSITION_H_ diff --git a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index 54fd709598..1becebf6e7 100644 --- a/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/small/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -1276,6 +1276,9 @@ o:value("", translate("Default")) o:value("h3") o:value("h2") o:value("h3,h2") +o:value("http/1.1") +o:value("h2,http/1.1") +o:value("h3,h2,http/1.1") o:value("spdy/3.1") o:value("h3,spdy/3.1") o:depends("type", "tuic") diff --git a/small/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm b/small/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm index 93b0e702a3..abba53cfe5 100644 --- a/small/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm +++ b/small/luci-app-ssr-plus/luasrc/view/shadowsocksr/ssrurl.htm @@ -844,7 +844,7 @@ function import_ssr_url(btn, urlname, sid) { var params = Object.fromEntries(new URLSearchParams(query)); var sipIndex = url0.indexOf("@"); - var userInfo = url0.substring(0, sipIndex); // 格式:uuid:password + var userInfo = decodeURIComponent(url0.substring(0, sipIndex)); // -- 如有Url编码进行解码,格式:uuid:password var hostPart = url0.substring(sipIndex + 1); // 格式:hostname:port var userInfoSplitIndex = userInfo.indexOf(":"); if(userInfoSplitIndex < 0) { @@ -887,13 +887,12 @@ function import_ssr_url(btn, urlname, sid) { document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_dual_stack')[0].checked = true; document.getElementsByName('cbid.shadowsocksr.' + sid + '.tuic_dual_stack')[0].dispatchEvent(event); if (params.ipstack_prefer && params.ipstack_prefer.trim() !== "") { - document.getElementsByName('cbid.shadowsocksr.' + sid + '.ipstack_prefer')[0].value = params.ipstack_prefer; + document.getElementsByName('cbid.shadowsocksr.' + sid + '.ipstack_prefer')[0].value = params.ipstack_prefer || ""; } } - if (params["allowInsecure"] === "1" || params["allowInsecure"] === "true") { - document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = true; - document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event); - } + document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].checked = + !!(params.allowInsecure ?? params.allowlnsecure ?? params.insecure); // 设置 insecure 为 true + document.getElementsByName('cbid.shadowsocksr.' + sid + '.insecure')[0].dispatchEvent(event); // 触发事件 if (param != undefined) { document.getElementsByName('cbid.shadowsocksr.' + sid + '.alias')[0].value = decodeURIComponent(param); } diff --git a/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua b/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua index d6e9c10b67..348b4dff46 100755 --- a/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua +++ b/small/luci-app-ssr-plus/root/usr/share/shadowsocksr/subscribe.lua @@ -997,10 +997,11 @@ local function processData(szType, content) local Info = content if Info:find("@") then local contents = split(Info, "@") - if contents[1]:find(":") then - local userinfo = split(contents[1], ":") - result.tuic_uuid = UrlDecode(userinfo[1]) - result.tuic_passwd = UrlDecode(userinfo[2]) + local userinfo_raw = UrlDecode(contents[1] or "") -- 如有Url编码进行解码 + if userinfo_raw:find(":") then + local userinfo = split(userinfo_raw, ":") + result.tuic_uuid = userinfo[1] + result.tuic_passwd = userinfo[2] end Info = (contents[2] or ""):gsub("/%?", "?") end @@ -1077,12 +1078,11 @@ local function processData(szType, content) end end - -- 处理 insecure 参数 - if params.allowInsecure then - if params.allowinsecure == "1" or params.allowinsecure == "0" then - result.insecure = params.allowInsecure - else - result.insecure = string.lower(params.allowinsecure) == "true" and "1" or "0" + -- 兼容 allowInsecure / allowlnsecure / insecure + if params.allowInsecure or params.allowlnsecure or params.insecure then + local insecure = params.allowInsecure or params.allowlnsecure or params.insecure + if insecure == true or insecure == "1" or insecure == "true" then + result.insecure = "1" end end end diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index f3dfcdab97..830992e419 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -12,7 +12,7 @@ PKG_MAINTAINER:=Tianling Shen include $(INCLUDE_DIR)/package.mk -GEOIP_VER:=202512050148 +GEOIP_VER:=202512201334 GEOIP_FILE:=geoip.dat.$(GEOIP_VER) define Download/geoip URL:=https://github.com/v2fly/geoip/releases/download/$(GEOIP_VER)/ @@ -21,13 +21,13 @@ define Download/geoip HASH:=6878dbacfb1fcb1ee022f63ed6934bcefc95a3c4ba10c88f1131fb88dbf7c337 endef -GEOSITE_VER:=20251219140209 +GEOSITE_VER:=20251220225755 GEOSITE_FILE:=dlc.dat.$(GEOSITE_VER) define Download/geosite URL:=https://github.com/v2fly/domain-list-community/releases/download/$(GEOSITE_VER)/ URL_FILE:=dlc.dat FILE:=$(GEOSITE_FILE) - HASH:=3449c57f7cd1f3f19f53840de554f14cfbe8787ec9e1a0ef9e2e910cefb3fcf2 + HASH:=c50ffac169736410caac0e90a5f22237e68df91c615ce26a6c5cf98caaa720df endef GEOSITE_IRAN_VER:=202512150045 diff --git a/v2rayn/v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml b/v2rayn/v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml index 368924795e..04870d4aab 100644 --- a/v2rayn/v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml +++ b/v2rayn/v2rayN/v2rayN.Desktop/Views/SubSettingWindow.axaml @@ -40,6 +40,14 @@ + + + + + + + + this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables); + + this.BindCommand(ViewModel, vm => vm.SubAddCmd, v => v.menuSubAdd2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare2).DisposeWith(disposables); }); } diff --git a/v2rayn/v2rayN/v2rayN/App.xaml b/v2rayn/v2rayN/v2rayN/App.xaml index e6b7e3af5b..01c206eac3 100644 --- a/v2rayn/v2rayN/v2rayN/App.xaml +++ b/v2rayn/v2rayN/v2rayN/App.xaml @@ -15,7 +15,7 @@ SecondaryColor="Lime" /> - 26 + 32 12 13 11 diff --git a/v2rayn/v2rayN/v2rayN/Views/SubSettingWindow.xaml b/v2rayn/v2rayN/v2rayN/Views/SubSettingWindow.xaml index 76985ec0dd..0a4be46996 100644 --- a/v2rayn/v2rayN/v2rayN/Views/SubSettingWindow.xaml +++ b/v2rayn/v2rayN/v2rayN/Views/SubSettingWindow.xaml @@ -93,6 +93,26 @@ HeadersVisibility="Column" IsReadOnly="True" Style="{StaticResource DefDataGrid}"> + + + + + + + + vm.SubDeleteCmd, v => v.menuSubDelete).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare).DisposeWith(disposables); + + this.BindCommand(ViewModel, vm => vm.SubAddCmd, v => v.menuSubAdd2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SubDeleteCmd, v => v.menuSubDelete2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SubEditCmd, v => v.menuSubEdit2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SubShareCmd, v => v.menuSubShare2).DisposeWith(disposables); }); WindowsUtils.SetDarkBorder(this, AppManager.Instance.Config.UiItem.CurrentTheme); } diff --git a/yt-dlp/test/test_utils.py b/yt-dlp/test/test_utils.py index 72f0eb7f76..ce865511c6 100644 --- a/yt-dlp/test/test_utils.py +++ b/yt-dlp/test/test_utils.py @@ -489,6 +489,10 @@ class TestUtil(unittest.TestCase): self.assertEqual(unified_timestamp('Wednesday 31 December 1969 18:01:26 MDT'), 86) self.assertEqual(unified_timestamp('12/31/1969 20:01:18 EDT', False), 78) + self.assertEqual(unified_timestamp('2026-01-01 00:00:00', tz_offset=0), 1767225600) + self.assertEqual(unified_timestamp('2026-01-01 00:00:00', tz_offset=8), 1767196800) + self.assertEqual(unified_timestamp('2026-01-01 00:00:00 +0800', tz_offset=-5), 1767196800) + def test_determine_ext(self): self.assertEqual(determine_ext('http://example.com/foo/bar.mp4/?download'), 'mp4') self.assertEqual(determine_ext('http://example.com/foo/bar/?download', None), None) diff --git a/yt-dlp/yt_dlp/utils/_utils.py b/yt-dlp/yt_dlp/utils/_utils.py index b0ca950248..edbbf6c650 100644 --- a/yt-dlp/yt_dlp/utils/_utils.py +++ b/yt-dlp/yt_dlp/utils/_utils.py @@ -1262,7 +1262,8 @@ def unified_strdate(date_str, day_first=True): return str(upload_date) -def unified_timestamp(date_str, day_first=True): +@partial_application +def unified_timestamp(date_str, day_first=True, tz_offset=0): if not isinstance(date_str, str): return None @@ -1270,7 +1271,8 @@ def unified_timestamp(date_str, day_first=True): r'(?i)[,|]|(mon|tues?|wed(nes)?|thu(rs)?|fri|sat(ur)?|sun)(day)?', '', date_str)) pm_delta = 12 if re.search(r'(?i)PM', date_str) else 0 - timezone, date_str = extract_timezone(date_str) + timezone, date_str = extract_timezone( + date_str, default=dt.timedelta(hours=tz_offset) if tz_offset else None) # Remove AM/PM + timezone date_str = re.sub(r'(?i)\s*(?:AM|PM)(?:\s+[A-Z]+)?', '', date_str)