From e2e637c9160a3b19c8744adafd8d23cec3e2b473 Mon Sep 17 00:00:00 2001 From: "github-action[bot]" Date: Sun, 1 Sep 2024 20:31:00 +0200 Subject: [PATCH] Update On Sun Sep 1 20:31:00 CEST 2024 --- .github/update.log | 1 + bbdown/BBDown.Core/Config.cs | 2 +- bbdown/BBDown.Core/Parser.cs | 45 +- clash-nyanpasu/.cargo/config.toml | 2 + .../.github/workflows/deps-build-linux.yaml | 66 +- clash-nyanpasu/frontend/nyanpasu/package.json | 6 +- .../frontend/nyanpasu/src/router.ts | 20 +- clash-nyanpasu/manifest/version.json | 4 +- clash-nyanpasu/package.json | 2 +- clash-nyanpasu/pnpm-lock.yaml | 132 +- echo/.gitignore | 1 + echo/go.mod | 12 + echo/go.sum | 34 + echo/internal/cli/flags.go | 4 +- echo/internal/cmgr/cmgr.go | 42 +- echo/internal/cmgr/config.go | 2 - echo/internal/cmgr/metric_man.go | 180 - echo/internal/cmgr/ms/ms.go | 118 + echo/internal/cmgr/syncer.go | 85 + echo/internal/config/config.go | 5 +- echo/internal/conn/relay_conn.go | 4 +- echo/internal/relay/conf/cfg.go | 36 +- echo/internal/relay/server.go | 6 +- echo/internal/transporter/base.go | 10 +- echo/internal/transporter/ws.go | 21 +- echo/internal/transporter/wss.go | 3 + echo/internal/web/handlers.go | 24 +- echo/internal/web/server.go | 129 +- echo/internal/web/templates/_head.html | 13 + echo/internal/web/templates/_metrics.html | 374 ++ echo/internal/web/templates/_navbar.html | 58 + echo/internal/web/templates/connection.html | 80 +- echo/internal/web/templates/index.html | 132 +- echo/internal/web/templates/metrics.html | 344 -- echo/internal/web/templates/rule_list.html | 17 +- echo/test/relay_test.go | 3 +- mieru/pkg/appctl/appctlpb/base.pb.go | 119 +- mieru/pkg/appctl/appctlpb/clientcfg.pb.go | 134 +- mieru/pkg/appctl/appctlpb/servercfg.pb.go | 54 +- mieru/pkg/appctl/client.go | 14 + mieru/pkg/appctl/client_test.go | 5 + mieru/pkg/appctl/proto/base.proto | 9 + mieru/pkg/appctl/proto/clientcfg.proto | 4 + mieru/pkg/appctl/proto/servercfg.proto | 4 + mieru/pkg/appctl/server.go | 9 + .../testdata/client_apply_config_1.json | 3 +- .../testdata/client_apply_config_2.json | 8 +- .../client_reject_invalid_http_port.json | 26 + .../testdata/client_reject_no_profiles.json | 5 + .../testdata/client_reject_no_servers.json | 14 + ...client_reject_socks5_auth_no_password.json | 34 + .../client_reject_socks5_auth_no_user.json | 34 + openwrt-packages/UnblockNeteaseMusic/Makefile | 4 +- .../model/cbi/passwall/client/global.lua | 56 +- .../luasrc/passwall/util_xray.lua | 2 + .../luci-app-passwall/po/zh-cn/passwall.po | 3 + .../root/usr/share/passwall/app.sh | 13 +- .../root/usr/share/passwall/rule_update.lua | 6 +- .../luasrc/passwall2/util_xray.lua | 4 +- .../model/cbi/passwall/client/global.lua | 56 +- .../luasrc/passwall/util_xray.lua | 2 + small/luci-app-passwall/po/zh-cn/passwall.po | 3 + .../root/usr/share/passwall/app.sh | 13 +- .../root/usr/share/passwall/rule_update.lua | 6 +- .../luasrc/passwall2/util_xray.lua | 4 +- small/v2ray-geodata/Makefile | 4 +- v2rayn/v2rayN/ProtosLib/ProtosLib.csproj | 4 +- .../ServiceLib/Common/DownloaderHelper.cs | 4 + v2rayn/v2rayN/ServiceLib/Enums/EViewAction.cs | 2 + .../ServiceLib/Handler/UpdateHandler.cs | 23 +- .../ServiceLib/Models/CheckUpdateItem.cs | 17 + .../ViewModels/CheckUpdateViewModel.cs | 323 ++ .../ViewModels/MainWindowViewModel.cs | 2 +- .../v2rayN/v2rayN/Views/CheckUpdateView.xaml | 112 + .../v2rayN/Views/CheckUpdateView.xaml.cs | 50 + v2rayn/v2rayN/v2rayN/Views/MainWindow.xaml | 23 +- v2rayn/v2rayN/v2rayN/Views/MainWindow.xaml.cs | 24 +- v2rayn/v2rayN/v2rayN/v2rayN.csproj | 4 +- xray-core/proxy/freedom/freedom.go | 30 +- yass/.tx/config | 56 + yass/README.md | 81 +- .../{values-zh => values-zh-rCN}/strings.xml | 7 +- yass/debian/changelog | 7 + yass/scripts/build-tun2proxy.sh | 22 - yass/scripts/fcntl.rs | 993 ------ yass/scripts/statfs.rs | 870 ----- yass/scripts/statvfs.rs | 172 - yass/scripts/unix.rs | 3117 ----------------- yass/src/gtk/yass_zh_CN.po | 15 +- yass/src/gtk4/yass_en.po | 4 +- yass/src/gtk4/yass_zh_CN.po | 15 +- yass/src/qt6/lang/yass_zh_CN.qm | Bin 3483 -> 3487 bytes yass/src/qt6/lang/yass_zh_CN.ts | 11 +- yass/tools/build.go | 3 + yass/yass.spec.in | 4 + 95 files changed, 2318 insertions(+), 6346 deletions(-) create mode 100644 clash-nyanpasu/.cargo/config.toml delete mode 100644 echo/internal/cmgr/metric_man.go create mode 100644 echo/internal/cmgr/ms/ms.go create mode 100644 echo/internal/cmgr/syncer.go create mode 100644 echo/internal/web/templates/_head.html create mode 100644 echo/internal/web/templates/_metrics.html create mode 100644 echo/internal/web/templates/_navbar.html delete mode 100644 echo/internal/web/templates/metrics.html create mode 100644 mieru/pkg/appctl/testdata/client_reject_invalid_http_port.json create mode 100644 mieru/pkg/appctl/testdata/client_reject_no_profiles.json create mode 100644 mieru/pkg/appctl/testdata/client_reject_no_servers.json create mode 100644 mieru/pkg/appctl/testdata/client_reject_socks5_auth_no_password.json create mode 100644 mieru/pkg/appctl/testdata/client_reject_socks5_auth_no_user.json create mode 100644 v2rayn/v2rayN/ServiceLib/Models/CheckUpdateItem.cs create mode 100644 v2rayn/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs create mode 100644 v2rayn/v2rayN/v2rayN/Views/CheckUpdateView.xaml create mode 100644 v2rayn/v2rayN/v2rayN/Views/CheckUpdateView.xaml.cs create mode 100644 yass/.tx/config rename yass/android/yass/src/main/res/{values-zh => values-zh-rCN}/strings.xml (94%) delete mode 100644 yass/scripts/fcntl.rs delete mode 100644 yass/scripts/statfs.rs delete mode 100644 yass/scripts/statvfs.rs delete mode 100644 yass/scripts/unix.rs diff --git a/.github/update.log b/.github/update.log index 0602b93c23..827d475170 100644 --- a/.github/update.log +++ b/.github/update.log @@ -750,3 +750,4 @@ Update On Tue Aug 27 20:32:11 CEST 2024 Update On Wed Aug 28 20:33:23 CEST 2024 Update On Fri Aug 30 20:32:59 CEST 2024 Update On Sat Aug 31 20:34:23 CEST 2024 +Update On Sun Sep 1 20:30:49 CEST 2024 diff --git a/bbdown/BBDown.Core/Config.cs b/bbdown/BBDown.Core/Config.cs index b75e116262..8d8cc553db 100644 --- a/bbdown/BBDown.Core/Config.cs +++ b/bbdown/BBDown.Core/Config.cs @@ -19,7 +19,7 @@ public static readonly Dictionary qualitys = new() { {"127","8K 超高清" }, {"126","杜比视界" }, {"125","HDR 真彩" }, {"120","4K 超清" }, {"116","1080P 高帧率" }, - {"112","1080P 高码率" }, {"80","1080P 高清" }, {"74","720P 高帧率" }, + {"112","1080P 高码率" }, {"100","智能修复" }, {"80","1080P 高清" }, {"74","720P 高帧率" }, {"64","720P 高清" }, {"48","720P 高清" }, {"32","480P 清晰" }, {"16","360P 流畅" }, {"5","144P 流畅" }, {"6","240P 流畅" } }; diff --git a/bbdown/BBDown.Core/Parser.cs b/bbdown/BBDown.Core/Parser.cs index be01947304..e200a490b3 100644 --- a/bbdown/BBDown.Core/Parser.cs +++ b/bbdown/BBDown.Core/Parser.cs @@ -30,7 +30,7 @@ namespace BBDown.Core if (appApi) return await AppHelper.DoReqAsync(aid, cid, epId, qn, bangumi, encoding, Config.TOKEN); string prefix = tvApi ? bangumi ? "api.snm0516.aisee.tv/pgc/player/api/playurltv" : "api.snm0516.aisee.tv/x/tv/playurl" - : bangumi ? $"{Config.HOST}/pgc/player/web/playurl" : "api.bilibili.com/x/player/wbi/playurl"; + : bangumi ? $"{Config.HOST}/pgc/player/web/v2/playurl" : "api.bilibili.com/x/player/wbi/playurl"; prefix = $"https://{prefix}?"; string api; @@ -48,7 +48,7 @@ namespace BBDown.Core { // 尝试提高可读性 StringBuilder apiBuilder = new(); - apiBuilder.Append($"avid={aid}&cid={cid}&fnval=4048&fnver=0&fourk=1"); + apiBuilder.Append($"support_multi_audio=true&from_client=BROWSER&avid={aid}&cid={cid}&fnval=4048&fnver=0&fourk=1"); if (Config.AREA != "") apiBuilder.Append($"&access_key={Config.TOKEN}&area={Config.AREA}"); apiBuilder.Append($"&otype=json&qn={qn}"); if (bangumi) apiBuilder.Append($"&module=bangumi&ep_id={epId}&session="); @@ -100,6 +100,8 @@ namespace BBDown.Core //调用解析 parsedResult.WebJsonString = await GetPlayJsonAsync(encoding, aidOri, aid, cid, epId, tvApi, intlApi, appApi, qn); + LogDebug(parsedResult.WebJsonString); + startParsing: var respJson = JsonDocument.Parse(parsedResult.WebJsonString); var data = respJson.RootElement; @@ -109,7 +111,7 @@ namespace BBDown.Core { int pDur = data.GetProperty("data").GetProperty("video_info").GetProperty("timelength").GetInt32() / 1000; var audio = data.GetProperty("data").GetProperty("video_info").GetProperty("dash_audio").EnumerateArray().ToList(); - foreach(var stream in data.GetProperty("data").GetProperty("video_info").GetProperty("stream_list").EnumerateArray()) + foreach (var stream in data.GetProperty("data").GetProperty("video_info").GetProperty("stream_list").EnumerateArray()) { if (stream.TryGetProperty("dash_video", out JsonElement dashVideo)) { @@ -133,7 +135,7 @@ namespace BBDown.Core } } - foreach(var node in audio) + foreach (var node in audio) { var urlList = new List() { node.GetProperty("base_url").ToString() }; urlList.AddRange(node.GetProperty("backup_url").EnumerateArray().Select(i => i.ToString())); @@ -160,9 +162,18 @@ namespace BBDown.Core } // data节点一次性判断完 string nodeName = null; - if (parsedResult.WebJsonString.Contains("\"result\":{")) nodeName = "result"; + if (parsedResult.WebJsonString.Contains("\"result\":{")) + { + nodeName = "result"; + + // v2 + if (parsedResult.WebJsonString.Contains("\"video_info\":{")) + { + nodeName = "video_info"; + } + } else if (parsedResult.WebJsonString.Contains("\"data\":{")) nodeName = "data"; - var root = nodeName == null ? data : data.GetProperty(nodeName); + var root = nodeName == null ? data : nodeName == "video_info" ? data.GetProperty("result").GetProperty(nodeName) : data.GetProperty(nodeName); bool bangumi = aidOri.StartsWith("ep:"); @@ -184,15 +195,15 @@ namespace BBDown.Core parsedResult.WebJsonString = await GetPlayJsonAsync(encoding, aidOri, aid, cid, epId, tvApi, intlApi, appApi, GetMaxQn()); respJson = JsonDocument.Parse(parsedResult.WebJsonString); data = respJson.RootElement; - root = nodeName == null ? data : data.GetProperty(nodeName); + root = nodeName == null ? data : nodeName == "video_info" ? data.GetProperty("result").GetProperty(nodeName) : data.GetProperty(nodeName); } try { video = root.GetProperty("dash").GetProperty("video").EnumerateArray().ToList(); } catch { } try { audio = root.GetProperty("dash").GetProperty("audio").EnumerateArray().ToList(); } catch { } if (appApi && bangumi) { - try { backgroundAudio = data.GetProperty("dubbing_info").GetProperty("background_audio").EnumerateArray().ToList(); } catch { } - try { roleAudio = data.GetProperty("dubbing_info").GetProperty("role_audio_list").EnumerateArray().ToList(); } catch { } + try { backgroundAudio = data.GetProperty("dubbing_info").GetProperty("background_audio").EnumerateArray().ToList(); } catch { } + try { roleAudio = data.GetProperty("dubbing_info").GetProperty("role_audio_list").EnumerateArray().ToList(); } catch { } } //处理杜比音频 try @@ -208,7 +219,7 @@ namespace BBDown.Core } } } - catch (Exception) { ; } + catch (Exception) {; } //处理Hi-Res无损 try @@ -232,7 +243,7 @@ namespace BBDown.Core foreach (var node in video) { var urlList = new List() { node.GetProperty("base_url").ToString() }; - if(node.TryGetProperty("backup_url", out JsonElement element) && element.ValueKind != JsonValueKind.Null) + if (node.TryGetProperty("backup_url", out JsonElement element) && element.ValueKind != JsonValueKind.Null) { urlList.AddRange(element.EnumerateArray().Select(i => i.ToString())); } @@ -346,7 +357,7 @@ namespace BBDown.Core //默认以最高清晰度解析 parsedResult.WebJsonString = await GetPlayJsonAsync(encoding, aidOri, aid, cid, epId, tvApi, intlApi, appApi, GetMaxQn()); data = JsonDocument.Parse(parsedResult.WebJsonString).RootElement; - root = nodeName == null ? data : data.GetProperty(nodeName); + root = nodeName == null ? data : nodeName == "video_info" ? data.GetProperty("result").GetProperty(nodeName) : data.GetProperty(nodeName); string quality = ""; string videoCodecid = ""; string url = ""; @@ -392,11 +403,11 @@ namespace BBDown.Core if (root.TryGetProperty("clip_info_list", out JsonElement clipList)) { parsedResult.ExtraPoints.AddRange(clipList.EnumerateArray().Select(clip => new ViewPoint() - { - title = clip.GetProperty("toastText").ToString().Replace("即将跳过", ""), - start = clip.GetProperty("start").GetInt32(), - end = clip.GetProperty("end").GetInt32() - }) + { + title = clip.GetProperty("toastText").ToString().Replace("即将跳过", ""), + start = clip.GetProperty("start").GetInt32(), + end = clip.GetProperty("end").GetInt32() + }) ); parsedResult.ExtraPoints.Sort((p1, p2) => p1.start.CompareTo(p2.start)); var newPoints = new List(); diff --git a/clash-nyanpasu/.cargo/config.toml b/clash-nyanpasu/.cargo/config.toml new file mode 100644 index 0000000000..3c32d251c5 --- /dev/null +++ b/clash-nyanpasu/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" diff --git a/clash-nyanpasu/.github/workflows/deps-build-linux.yaml b/clash-nyanpasu/.github/workflows/deps-build-linux.yaml index db40d5f3e7..5890754135 100644 --- a/clash-nyanpasu/.github/workflows/deps-build-linux.yaml +++ b/clash-nyanpasu/.github/workflows/deps-build-linux.yaml @@ -14,6 +14,12 @@ on: required: true type: string + aarch64: + description: "Build for aarch64" + required: false + type: boolean + default: false + workflow_call: inputs: nightly: @@ -27,9 +33,15 @@ on: required: true type: string + aarch64: + description: "Build for aarch64" + required: false + type: boolean + default: false + jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 # 需要手动升级到 24.04 steps: - name: Checkout repository @@ -40,6 +52,33 @@ jobs: rustup install stable --profile minimal --no-self-update rustup default stable + - name: Setup aarch64 Toolchain + if: ${{ inputs.aarch64 == true }} + run: | + rustup target add aarch64-unknown-linux-gnu + sudo apt install gcc-aarch64-linux-gnu -y + sudo dpkg --add-architecture arm64 + cat <(); -export const { useModals, useNavigate, useParams } = hooks< - Path, - Params, - ModalPath ->(); -export const { redirect } = utils(); +export const { Link, Navigate } = components() +export const { useModals, useNavigate, useParams } = hooks() +export const { redirect } = utils() diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index 86fd1e301b..b28903258e 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.18.7", - "mihomo_alpha": "alpha-08ac9a3", + "mihomo_alpha": "alpha-fdd2b7a", "clash_rs": "v0.3.0", "clash_premium": "2023-09-05-gdcc8d87" }, @@ -36,5 +36,5 @@ "darwin-x64": "clash-darwin-amd64-n{}.gz" } }, - "updated_at": "2024-08-30T22:20:27.034Z" + "updated_at": "2024-08-31T22:20:37.996Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index 7278c9e29e..9e17ab60ff 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -83,7 +83,7 @@ "knip": "5.28.0", "lint-staged": "15.2.9", "npm-run-all2": "6.2.2", - "postcss": "8.4.41", + "postcss": "8.4.42", "postcss-html": "1.7.0", "postcss-import": "16.1.0", "postcss-scss": "4.0.9", diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 4b40c3cd78..f9de9bdfb7 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -51,7 +51,7 @@ importers: version: 8.3.0(eslint@8.57.0)(typescript@5.5.4) autoprefixer: specifier: 10.4.20 - version: 10.4.20(postcss@8.4.41) + version: 10.4.20(postcss@8.4.42) conventional-changelog-conventionalcommits: specifier: 8.0.0 version: 8.0.0 @@ -107,17 +107,17 @@ importers: specifier: 6.2.2 version: 6.2.2 postcss: - specifier: 8.4.41 - version: 8.4.41 + specifier: 8.4.42 + version: 8.4.42 postcss-html: specifier: 1.7.0 version: 1.7.0 postcss-import: specifier: 16.1.0 - version: 16.1.0(postcss@8.4.41) + version: 16.1.0(postcss@8.4.42) postcss-scss: specifier: 4.0.9 - version: 4.0.9(postcss@8.4.41) + version: 4.0.9(postcss@8.4.42) prettier: specifier: 3.3.3 version: 3.3.3 @@ -288,8 +288,8 @@ importers: specifier: 2.2.5 version: 2.2.5(react@19.0.0-rc-e948a5ac-20240807) virtua: - specifier: 0.34.1 - version: 0.34.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807) + specifier: 0.34.2 + version: 0.34.2(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807) devDependencies: '@csstools/normalize.css': specifier: 12.1.1 @@ -301,8 +301,8 @@ importers: specifier: 11.13.3 version: 11.13.3(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@iconify/json': - specifier: 2.2.242 - version: 2.2.242 + specifier: 2.2.243 + version: 2.2.243 '@types/react': specifier: npm:types-react@rc version: types-react@19.0.0-rc.1 @@ -322,8 +322,8 @@ importers: specifier: 1.77.8 version: 1.77.8 shiki: - specifier: 1.15.1 - version: 1.15.1 + specifier: 1.15.2 + version: 1.15.2 tailwindcss-textshadow: specifier: 2.1.3 version: 2.1.3 @@ -341,7 +341,7 @@ importers: version: vite-plugin-monaco-editor-new@1.1.3(monaco-editor@0.51.0) vite-plugin-sass-dts: specifier: 1.3.25 - version: 1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 1.3.25(postcss@8.4.42)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) vite-plugin-svgr: specifier: 4.2.0 version: 4.2.0(rollup@4.21.0)(typescript@5.5.4)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) @@ -1389,8 +1389,8 @@ packages: '@vue/compiler-sfc': optional: true - '@iconify/json@2.2.242': - resolution: {integrity: sha512-cS6eYdx1C1GhqaZm25ztH5yoghCaTXGJBeseUkS259GxxX9obtGLLk0yy+twxpNCD5/F9gjbgxh46BjNWsHtwg==} + '@iconify/json@2.2.243': + resolution: {integrity: sha512-92pXEKdjDmH8sV3fZwJTxifKpJtp3ie8KD7oCqHRJh/Z+CoGm3bzDcK5UnWs5G5EDbu00kYVcSGM4jRnY9HgGQ==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -2048,8 +2048,8 @@ packages: '@rushstack/ts-command-line@4.22.3': resolution: {integrity: sha512-edMpWB3QhFFZ4KtSzS8WNjBgR4PXPPOVrOHMbb7kNpmQ1UFS9HdVtjCXg1H5fG+xYAbeE+TMPcVPUyX2p84STA==} - '@shikijs/core@1.15.1': - resolution: {integrity: sha512-DwkQTDNlhr7PwZMJswdvWIKts+2mqjIn8txByr88fhBRBtUSsIQR43RRoATjRrbeu4hyNTSTMBdxgp/vlxnxvA==} + '@shikijs/core@1.15.2': + resolution: {integrity: sha512-hi6XZuwHYn6bU4wtXZxST8ynM55aiU2+rVU9aPIrSxqKmEKl4d65puwGsggwcZWTET+7zGXKe7AUj46iQ8Aq8w==} '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} @@ -5465,6 +5465,10 @@ packages: resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==} engines: {node: ^10 || ^12 || >=14} + postcss@8.4.42: + resolution: {integrity: sha512-hywKUQB9Ra4dR1mGhldy5Aj1X3MWDSIA1cEi+Uy0CjheLvP6Ual5RlwMCh8i/X121yEDLDIKBsrCQ8ba3FDMfQ==} + engines: {node: ^10 || ^12 || >=14} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -5927,8 +5931,8 @@ packages: shell-quote@1.8.1: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} - shiki@1.15.1: - resolution: {integrity: sha512-QPtVwbafyHmH9Z90iEZgZL4BhqFh5RMnRq2Bic0Cqp5lgbpbkn4nNmed0zzXbh/yPFs2PpkCviM9qcrbN+9zAA==} + shiki@1.15.2: + resolution: {integrity: sha512-M+7QZQZiZw/cZeizrC/yryG3eeG8pTUhu7ZaHxVyzPNFIRIlN46YBciquoNPCiXiwLnx6JB62f3lSuSYQrus1w==} side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} @@ -6557,8 +6561,8 @@ packages: vfile@6.0.1: resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} - virtua@0.34.1: - resolution: {integrity: sha512-8KrAoZboqvMdAjtaaODJQrsKNFhsf1mgGF1tmWRh5J0PTgeBCG9Mci/rep/YT3A7CbiTfdq+yThJ2SbatqZ+Ug==} + virtua@0.34.2: + resolution: {integrity: sha512-r43hQsryJRqVChrf6Go52rScyc89szl/IxFclOJRXF5qd6fv1Lzb68K51htI1NhtaPk+GQxuS2Gd21YL5ZGeDg==} peerDependencies: react: npm:react@rc react-dom: npm:react-dom@rc @@ -7675,7 +7679,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@iconify/json@2.2.242': + '@iconify/json@2.2.243': dependencies: '@iconify/types': 2.0.0 pathe: 1.1.2 @@ -8341,7 +8345,7 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@shikijs/core@1.15.1': + '@shikijs/core@1.15.2': dependencies: '@types/hast': 3.0.4 @@ -8785,11 +8789,11 @@ snapshots: '@types/postcss-modules-local-by-default@4.0.2': dependencies: - postcss: 8.4.41 + postcss: 8.4.42 '@types/postcss-modules-scope@3.0.4': dependencies: - postcss: 8.4.41 + postcss: 8.4.42 '@types/prop-types@15.7.12': {} @@ -9166,14 +9170,14 @@ snapshots: dependencies: tslib: 2.6.2 - autoprefixer@10.4.20(postcss@8.4.41): + autoprefixer@10.4.20(postcss@8.4.42): dependencies: browserslist: 4.23.3 caniuse-lite: 1.0.30001646 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.1 - postcss: 8.4.41 + postcss: 8.4.42 postcss-value-parser: 4.2.0 autoprefixer@9.8.8: @@ -11992,19 +11996,19 @@ snapshots: dependencies: htmlparser2: 8.0.2 js-tokens: 9.0.0 - postcss: 8.4.41 - postcss-safe-parser: 6.0.0(postcss@8.4.41) + postcss: 8.4.42 + postcss-safe-parser: 6.0.0(postcss@8.4.42) - postcss-import@15.1.0(postcss@8.4.41): + postcss-import@15.1.0(postcss@8.4.42): dependencies: - postcss: 8.4.41 + postcss: 8.4.42 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 - postcss-import@16.1.0(postcss@8.4.41): + postcss-import@16.1.0(postcss@8.4.42): dependencies: - postcss: 8.4.41 + postcss: 8.4.42 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 @@ -12014,10 +12018,10 @@ snapshots: camelcase-css: 2.0.1 postcss: 7.0.39 - postcss-js@4.0.1(postcss@8.4.41): + postcss-js@4.0.1(postcss@8.4.42): dependencies: camelcase-css: 2.0.1 - postcss: 8.4.41 + postcss: 8.4.42 postcss-load-config@3.1.4(postcss@8.4.38): dependencies: @@ -12026,12 +12030,12 @@ snapshots: optionalDependencies: postcss: 8.4.38 - postcss-load-config@4.0.2(postcss@8.4.41): + postcss-load-config@4.0.2(postcss@8.4.42): dependencies: lilconfig: 3.1.2 yaml: 2.5.0 optionalDependencies: - postcss: 8.4.41 + postcss: 8.4.42 postcss-media-query-parser@0.2.3: {} @@ -12056,24 +12060,24 @@ snapshots: postcss: 7.0.39 postcss-selector-parser: 6.1.2 - postcss-nested@6.0.1(postcss@8.4.41): + postcss-nested@6.0.1(postcss@8.4.42): dependencies: - postcss: 8.4.41 + postcss: 8.4.42 postcss-selector-parser: 6.1.2 postcss-resolve-nested-selector@0.1.6: {} - postcss-safe-parser@6.0.0(postcss@8.4.41): + postcss-safe-parser@6.0.0(postcss@8.4.42): dependencies: - postcss: 8.4.41 + postcss: 8.4.42 - postcss-safe-parser@7.0.0(postcss@8.4.41): + postcss-safe-parser@7.0.0(postcss@8.4.42): dependencies: - postcss: 8.4.41 + postcss: 8.4.42 - postcss-scss@4.0.9(postcss@8.4.41): + postcss-scss@4.0.9(postcss@8.4.42): dependencies: - postcss: 8.4.41 + postcss: 8.4.42 postcss-selector-parser@6.0.16: dependencies: @@ -12095,9 +12099,9 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-sorting@8.0.2(postcss@8.4.41): + postcss-sorting@8.0.2(postcss@8.4.42): dependencies: - postcss: 8.4.41 + postcss: 8.4.42 postcss-value-parser@3.3.1: {} @@ -12132,6 +12136,12 @@ snapshots: picocolors: 1.0.1 source-map-js: 1.2.0 + postcss@8.4.42: + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + prelude-ls@1.2.1: {} prepend-http@1.0.4: {} @@ -12583,9 +12593,9 @@ snapshots: shell-quote@1.8.1: {} - shiki@1.15.1: + shiki@1.15.2: dependencies: - '@shikijs/core': 1.15.1 + '@shikijs/core': 1.15.2 '@types/hast': 3.0.4 side-channel@1.0.6: @@ -12804,8 +12814,8 @@ snapshots: stylelint-order@6.0.4(stylelint@16.9.0(typescript@5.5.4)): dependencies: - postcss: 8.4.41 - postcss-sorting: 8.0.2(postcss@8.4.41) + postcss: 8.4.42 + postcss-sorting: 8.0.2(postcss@8.4.42) stylelint: 16.9.0(typescript@5.5.4) stylelint-scss@6.5.1(stylelint@16.9.0(typescript@5.5.4)): @@ -12848,9 +12858,9 @@ snapshots: micromatch: 4.0.8 normalize-path: 3.0.0 picocolors: 1.0.1 - postcss: 8.4.41 + postcss: 8.4.42 postcss-resolve-nested-selector: 0.1.6 - postcss-safe-parser: 7.0.0(postcss@8.4.41) + postcss-safe-parser: 7.0.0(postcss@8.4.42) postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 resolve-from: 5.0.0 @@ -12989,11 +12999,11 @@ snapshots: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.0.1 - postcss: 8.4.41 - postcss-import: 15.1.0(postcss@8.4.41) - postcss-js: 4.0.1(postcss@8.4.41) - postcss-load-config: 4.0.2(postcss@8.4.41) - postcss-nested: 6.0.1(postcss@8.4.41) + postcss: 8.4.42 + postcss-import: 15.1.0(postcss@8.4.42) + postcss-js: 4.0.1(postcss@8.4.42) + postcss-load-config: 4.0.2(postcss@8.4.42) + postcss-nested: 6.0.1(postcss@8.4.42) postcss-selector-parser: 6.1.1 resolve: 1.22.8 sucrase: 3.35.0 @@ -13374,7 +13384,7 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - virtua@0.34.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807): + virtua@0.34.2(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807): optionalDependencies: react: 19.0.0-rc-e948a5ac-20240807 react-dom: 19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807) @@ -13404,10 +13414,10 @@ snapshots: esbuild: 0.19.12 monaco-editor: 0.51.0 - vite-plugin-sass-dts@1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): + vite-plugin-sass-dts@1.3.25(postcss@8.4.42)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): dependencies: - postcss: 8.4.41 - postcss-js: 4.0.1(postcss@8.4.41) + postcss: 8.4.42 + postcss-js: 4.0.1(postcss@8.4.42) prettier: 3.3.3 sass: 1.77.8 vite: 5.4.2(@types/node@22.5.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) diff --git a/echo/.gitignore b/echo/.gitignore index 1b1813923d..6d398564a7 100644 --- a/echo/.gitignore +++ b/echo/.gitignore @@ -28,3 +28,4 @@ cmd/test/ localdev/ .vscode/settings.json +.zed/ diff --git a/echo/go.mod b/echo/go.mod index d65d65f76e..2ff9d23c94 100644 --- a/echo/go.mod +++ b/echo/go.mod @@ -12,6 +12,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.7 github.com/juju/ratelimit v1.0.2 github.com/labstack/echo/v4 v4.12.0 + github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.20.0 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.55.0 @@ -27,6 +28,7 @@ require ( golang.org/x/time v0.6.0 google.golang.org/grpc v1.65.0 gopkg.in/yaml.v3 v3.0.1 + modernc.org/sqlite v1.32.0 ) require ( @@ -43,6 +45,7 @@ require ( github.com/dennwc/btrfs v0.0.0-20240418142341-0167142bde7a // indirect github.com/dennwc/ioctl v1.0.0 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/ema/qdisc v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -62,6 +65,7 @@ require ( github.com/gorilla/websocket v1.5.3 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-envparse v0.1.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hodgesds/perf-utils v0.7.0 // indirect github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973 // indirect github.com/josharian/native v1.1.0 // indirect @@ -81,6 +85,7 @@ require ( github.com/mdlayher/wifi v0.2.0 // indirect github.com/miekg/dns v1.1.61 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect github.com/onsi/ginkgo/v2 v2.19.0 // indirect github.com/opencontainers/selinux v1.11.0 // indirect github.com/oschwald/maxminddb-golang v1.12.0 // indirect @@ -92,6 +97,7 @@ require ( github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/quic-go v0.45.1 // indirect github.com/refraction-networking/utls v1.6.7 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect @@ -127,4 +133,10 @@ require ( gvisor.dev/gvisor v0.0.0-20231202080848-1f7806d17489 // indirect howett.net/plist v1.0.1 // indirect lukechampine.com/blake3 v1.3.0 // indirect + modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect + modernc.org/libc v1.55.3 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect ) diff --git a/echo/go.sum b/echo/go.sum index e85edcbcc4..a45dc09993 100644 --- a/echo/go.sum +++ b/echo/go.sum @@ -47,6 +47,8 @@ github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fp github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 h1:y7y0Oa6UawqTFPCDw9JG6pdKt4F9pAhHv0B7FMGaGD0= github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/ema/qdisc v1.0.0 h1:EHLG08FVRbWLg8uRICa3xzC9Zm0m7HyMHfXobWFnXYg= github.com/ema/qdisc v1.0.0/go.mod h1:FhIc0fLYi7f+lK5maMsesDqwYojIOh3VfRs8EVd5YJQ= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= @@ -128,6 +130,8 @@ github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB1 github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hodgesds/perf-utils v0.7.0 h1:7KlHGMuig4FRH5fNw68PV6xLmgTe7jKs9hgAcEAbioU= github.com/hodgesds/perf-utils v0.7.0/go.mod h1:LAklqfDadNKpkxoAJNHpD5tkY0rkZEVdnCEWN5k4QJY= github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973 h1:hk4LPqXIY/c9XzRbe7dA6qQxaT6Axcbny0L/G5a4owQ= @@ -192,6 +196,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= @@ -238,6 +244,8 @@ github.com/quic-go/quic-go v0.45.1 h1:tPfeYCk+uZHjmDRwHHQmvHRYL2t44ROTujLeFVBmjC github.com/quic-go/quic-go v0.45.1/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM= github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= @@ -458,5 +466,31 @@ howett.net/plist v1.0.1 h1:37GdZ8tP09Q35o9ych3ehygcsL+HqKSwzctveSlarvM= howett.net/plist v1.0.1/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= +modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= +modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= +modernc.org/ccgo/v4 v4.19.2/go.mod h1:ysS3mxiMV38XGRTTcgo0DQTeTmAO4oCmJl1nX9VFI3s= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw= +modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= +modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= +modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= +modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= +modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= +modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/echo/internal/cli/flags.go b/echo/internal/cli/flags.go index 51c425c438..5870888603 100644 --- a/echo/internal/cli/flags.go +++ b/echo/internal/cli/flags.go @@ -31,7 +31,7 @@ var RootFlags = []cli.Flag{ &cli.StringFlag{ Name: "lt,listen_type", Value: "raw", - Usage: "监听类型,可选项有 raw,ws,wss,mwss", + Usage: "监听类型,可选项有 raw,ws,wss", EnvVars: []string{"EHCO_LISTEN_TYPE"}, Destination: (*string)(&ListenType), Required: false, @@ -45,7 +45,7 @@ var RootFlags = []cli.Flag{ &cli.StringFlag{ Name: "tt,transport_type", Value: "raw", - Usage: "传输类型,可选选有 raw,ws,wss,mwss", + Usage: "传输类型,可选选有 raw,ws,wss", EnvVars: []string{"EHCO_TRANSPORT_TYPE"}, Destination: (*string)(&TransportType), }, diff --git a/echo/internal/cmgr/cmgr.go b/echo/internal/cmgr/cmgr.go index d2126c32c6..b81a3510d4 100644 --- a/echo/internal/cmgr/cmgr.go +++ b/echo/internal/cmgr/cmgr.go @@ -2,10 +2,13 @@ package cmgr import ( "context" + "os" + "path/filepath" "sort" "sync" "time" + "github.com/Ehco1996/ehco/internal/cmgr/ms" "github.com/Ehco1996/ehco/internal/conn" "github.com/Ehco1996/ehco/pkg/metric_reader" "go.uber.org/zap" @@ -35,7 +38,8 @@ type Cmgr interface { // Start starts the connection manager. Start(ctx context.Context, errCH chan error) - QueryNodeMetrics(ctx context.Context, req *QueryNodeMetricsReq) ([]metric_reader.NodeMetrics, error) + // Metrics related + QueryNodeMetrics(ctx context.Context, req *ms.QueryNodeMetricsReq) (*ms.QueryNodeMetricsResp, error) } type cmgrImpl struct { @@ -47,11 +51,11 @@ type cmgrImpl struct { activeConnectionsMap map[string][]conn.RelayConn closedConnectionsMap map[string][]conn.RelayConn + ms *ms.MetricsStore mr metric_reader.Reader - ms *MetricsStore } -func NewCmgr(cfg *Config) Cmgr { +func NewCmgr(cfg *Config) (Cmgr, error) { cmgr := &cmgrImpl{ cfg: cfg, l: zap.S().Named("cmgr"), @@ -60,12 +64,16 @@ func NewCmgr(cfg *Config) Cmgr { } if cfg.NeedMetrics() { cmgr.mr = metric_reader.NewReader(cfg.MetricsURL) - // 当前只能存储 24h 的 metrics,之后再优化 - bufSize := 60 * 60 * 24 / cfg.SyncInterval - cmgr.l.Infof("metrics buffer size: %d", bufSize) - cmgr.ms = NewMetricsStore(bufSize, time.Hour*24) + + homeDir, _ := os.UserHomeDir() + dbPath := filepath.Join(homeDir, ".ehco", "metrics.db") + ms, err := ms.NewMetricsStore(dbPath) + if err != nil { + return nil, err + } + cmgr.ms = ms } - return cmgr + return cmgr, nil } func (cm *cmgrImpl) ListConnections(connType string, page, pageSize int) []conn.RelayConn { @@ -192,3 +200,21 @@ func (cm *cmgrImpl) Start(ctx context.Context, errCH chan error) { } } } + +func (cm *cmgrImpl) QueryNodeMetrics(ctx context.Context, req *ms.QueryNodeMetricsReq) (*ms.QueryNodeMetricsResp, error) { + num := -1 // default to return all metrics + if req.Latest { + m, err := cm.mr.ReadOnce(ctx) + if err != nil { + return nil, err + } + if err := cm.ms.AddNodeMetric(m); err != nil { + return nil, err + } + num = 1 + } + + startTime := time.Unix(req.StartTimestamp, 0) + endTime := time.Unix(req.EndTimestamp, 0) + return cm.ms.QueryNodeMetric(startTime, endTime, num) +} diff --git a/echo/internal/cmgr/config.go b/echo/internal/cmgr/config.go index 12e475cf63..e588f14d30 100644 --- a/echo/internal/cmgr/config.go +++ b/echo/internal/cmgr/config.go @@ -1,7 +1,5 @@ package cmgr -var DummyConfig = &Config{} - type Config struct { SyncURL string MetricsURL string diff --git a/echo/internal/cmgr/metric_man.go b/echo/internal/cmgr/metric_man.go deleted file mode 100644 index c91bb8dad9..0000000000 --- a/echo/internal/cmgr/metric_man.go +++ /dev/null @@ -1,180 +0,0 @@ -package cmgr - -import ( - "context" - "sync" - "time" - - "github.com/Ehco1996/ehco/internal/conn" - "github.com/Ehco1996/ehco/internal/constant" - myhttp "github.com/Ehco1996/ehco/pkg/http" - "github.com/Ehco1996/ehco/pkg/metric_reader" - "go.uber.org/zap" -) - -type StatsPerRule struct { - RelayLabel string `json:"relay_label"` - - Up int64 `json:"up_bytes"` - Down int64 `json:"down_bytes"` - ConnectionCnt int `json:"connection_count"` - HandShakeLatency int64 `json:"latency_in_ms"` -} - -type VersionInfo struct { - Version string `json:"version"` - ShortCommit string `json:"short_commit"` -} - -type syncReq struct { - Version VersionInfo `json:"version"` - Node metric_reader.NodeMetrics `json:"node"` - Stats []StatsPerRule `json:"stats"` -} - -type MetricsStore struct { - mutex sync.RWMutex - - metrics []metric_reader.NodeMetrics - - bufSize int - clearDuration time.Duration -} - -func NewMetricsStore(bufSize int, clearDuration time.Duration) *MetricsStore { - return &MetricsStore{ - metrics: make([]metric_reader.NodeMetrics, bufSize), - clearDuration: clearDuration, - bufSize: bufSize, - } -} - -func (ms *MetricsStore) Add(m *metric_reader.NodeMetrics) { - ms.mutex.Lock() - defer ms.mutex.Unlock() - - // 直接添加新的 metric,假设它是最新的 - ms.metrics = append(ms.metrics, *m) - - // 清理旧数据 - cutoffTime := time.Now().Add(-ms.clearDuration) - for i, metric := range ms.metrics { - if metric.SyncTime.After(cutoffTime) { - ms.metrics = ms.metrics[i:] - break - } - } -} - -func (ms *MetricsStore) Query(startTime, endTime time.Time) []metric_reader.NodeMetrics { - ms.mutex.RLock() - defer ms.mutex.RUnlock() - - var result []metric_reader.NodeMetrics - for i := len(ms.metrics) - 1; i >= 0; i-- { - if ms.metrics[i].SyncTime.Before(startTime) { - break - } - if !ms.metrics[i].SyncTime.After(endTime) { - result = append(result, ms.metrics[i]) - } - } - - // 反转结果,使其按时间升序排列 - for i := 0; i < len(result)/2; i++ { - j := len(result) - 1 - i - result[i], result[j] = result[j], result[i] - } - - return result -} - -type QueryNodeMetricsReq struct { - TimeRange string `json:"time_range"` // 15min/30min/1h/6h/12h/24h - Latest bool `json:"latest"` // whether to refresh the cache and get the latest data -} - -func (cm *cmgrImpl) syncOnce(ctx context.Context) error { - cm.l.Infof("sync once total closed connections: %d", cm.countClosedConnection()) - // todo: opt lock - cm.lock.Lock() - - shortCommit := constant.GitRevision - if len(constant.GitRevision) > 7 { - shortCommit = constant.GitRevision[:7] - } - req := syncReq{ - Stats: []StatsPerRule{}, - Version: VersionInfo{Version: constant.Version, ShortCommit: shortCommit}, - } - - if cm.cfg.NeedMetrics() { - metrics, err := cm.mr.ReadOnce(ctx) - if err != nil { - cm.l.Errorf("read metrics failed: %v", err) - } else { - req.Node = *metrics - cm.ms.Add(metrics) - } - } - - for label, conns := range cm.closedConnectionsMap { - s := StatsPerRule{ - RelayLabel: label, - } - var totalLatency int64 - for _, c := range conns { - s.ConnectionCnt++ - s.Up += c.GetStats().Up - s.Down += c.GetStats().Down - totalLatency += c.GetStats().HandShakeLatency.Milliseconds() - } - if s.ConnectionCnt > 0 { - s.HandShakeLatency = totalLatency / int64(s.ConnectionCnt) - } - req.Stats = append(req.Stats, s) - } - cm.closedConnectionsMap = make(map[string][]conn.RelayConn) - cm.lock.Unlock() - - if cm.cfg.NeedSync() { - cm.l.Debug("syncing data to server", zap.Any("data", req)) - return myhttp.PostJSONWithRetry(cm.cfg.SyncURL, &req) - } else { - cm.l.Debugf("remove %d closed connections", len(req.Stats)) - } - return nil -} - -func getTimeRangeDuration(timeRange string) time.Duration { - switch timeRange { - case "15min": - return 15 * time.Minute - case "30min": - return 30 * time.Minute - case "1h": - return 1 * time.Hour - case "6h": - return 6 * time.Hour - case "12h": - return 12 * time.Hour - case "24h": - return 24 * time.Hour - default: - return 15 * time.Minute - } -} - -func (cm *cmgrImpl) QueryNodeMetrics(ctx context.Context, req *QueryNodeMetricsReq) ([]metric_reader.NodeMetrics, error) { - if req.Latest { - m, err := cm.mr.ReadOnce(ctx) - if err != nil { - return nil, err - } - cm.ms.Add(m) - return []metric_reader.NodeMetrics{*m}, nil - } - - startTime := time.Now().Add(-getTimeRangeDuration(req.TimeRange)) - return cm.ms.Query(startTime, time.Now()), nil -} diff --git a/echo/internal/cmgr/ms/ms.go b/echo/internal/cmgr/ms/ms.go new file mode 100644 index 0000000000..e57a405320 --- /dev/null +++ b/echo/internal/cmgr/ms/ms.go @@ -0,0 +1,118 @@ +package ms + +import ( + "database/sql" + "os" + "path/filepath" + "time" + + "go.uber.org/zap" + _ "modernc.org/sqlite" + + "github.com/Ehco1996/ehco/pkg/metric_reader" +) + +type NodeMetrics struct { + Timestamp int64 `json:"timestamp"` + + CPUUsage float64 `json:"cpu_usage"` + MemoryUsage float64 `json:"memory_usage"` + DiskUsage float64 `json:"disk_usage"` + NetworkIn float64 `json:"network_in"` + NetworkOut float64 `json:"network_out"` +} + +type QueryNodeMetricsReq struct { + StartTimestamp int64 `json:"start_ts"` + EndTimestamp int64 `json:"end_ts"` + + Latest bool `json:"latest"` // whether to refresh the cache and get the latest data +} +type QueryNodeMetricsResp struct { + TOTAL int `json:"total"` + Data []NodeMetrics `json:"data"` +} + +type MetricsStore struct { + db *sql.DB + dbPath string + + l *zap.SugaredLogger +} + +func NewMetricsStore(dbPath string) (*MetricsStore, error) { + // ensure the directory exists + dirPath := filepath.Dir(dbPath) + if err := os.MkdirAll(dirPath, 0o755); err != nil { + return nil, err + } + // create db file if not exists + if _, err := os.Stat(dbPath); os.IsNotExist(err) { + f, err := os.Create(dbPath) + if err != nil { + return nil, err + } + if err := f.Close(); err != nil { + return nil, err + } + } + + db, err := sql.Open("sqlite", dbPath) + if err != nil { + return nil, err + } + ms := &MetricsStore{dbPath: dbPath, db: db, l: zap.S().Named("ms")} + if err := ms.initDB(); err != nil { + return nil, err + } + return ms, nil +} + +func (ms *MetricsStore) initDB() error { + // init NodeMetrics table + _, err := ms.db.Exec(` + CREATE TABLE IF NOT EXISTS node_metrics ( + timestamp INTEGER, + cpu_usage REAL, + memory_usage REAL, + disk_usage REAL, + network_in REAL, + network_out REAL, + PRIMARY KEY (timestamp) + ) + `) + return err +} + +func (ms *MetricsStore) AddNodeMetric(m *metric_reader.NodeMetrics) error { + _, err := ms.db.Exec(` + INSERT OR REPLACE INTO node_metrics (timestamp, cpu_usage, memory_usage, disk_usage, network_in, network_out) + VALUES (?, ?, ?, ?, ?, ?) +`, m.SyncTime.Unix(), m.CpuUsagePercent, m.MemoryUsagePercent, m.DiskUsagePercent, m.NetworkReceiveBytesRate, m.NetworkTransmitBytesRate) + return err +} + +func (ms *MetricsStore) QueryNodeMetric(startTime, endTime time.Time, num int) (*QueryNodeMetricsResp, error) { + rows, err := ms.db.Query(` + SELECT timestamp, cpu_usage, memory_usage, disk_usage, network_in, network_out + FROM node_metrics + WHERE timestamp >= ? AND timestamp <= ? + ORDER BY timestamp DESC + LIMIT ? +`, startTime.Unix(), endTime.Unix(), num) + if err != nil { + return nil, err + } + defer rows.Close() //nolint:errcheck + + var resp QueryNodeMetricsResp + for rows.Next() { + var m NodeMetrics + if err := rows.Scan(&m.Timestamp, &m.CPUUsage, &m.MemoryUsage, &m.DiskUsage, &m.NetworkIn, &m.NetworkOut); err != nil { + return nil, err + } + resp.Data = append(resp.Data, m) + } + resp.TOTAL = len(resp.Data) + return &resp, nil +} diff --git a/echo/internal/cmgr/syncer.go b/echo/internal/cmgr/syncer.go new file mode 100644 index 0000000000..067a6337f5 --- /dev/null +++ b/echo/internal/cmgr/syncer.go @@ -0,0 +1,85 @@ +package cmgr + +import ( + "context" + + "github.com/Ehco1996/ehco/internal/conn" + "github.com/Ehco1996/ehco/internal/constant" + myhttp "github.com/Ehco1996/ehco/pkg/http" + "github.com/Ehco1996/ehco/pkg/metric_reader" + "go.uber.org/zap" +) + +type StatsPerRule struct { + RelayLabel string `json:"relay_label"` + + Up int64 `json:"up_bytes"` + Down int64 `json:"down_bytes"` + ConnectionCnt int `json:"connection_count"` + HandShakeLatency int64 `json:"latency_in_ms"` +} + +type VersionInfo struct { + Version string `json:"version"` + ShortCommit string `json:"short_commit"` +} + +type syncReq struct { + Version VersionInfo `json:"version"` + Node metric_reader.NodeMetrics `json:"node"` + Stats []StatsPerRule `json:"stats"` +} + +func (cm *cmgrImpl) syncOnce(ctx context.Context) error { + cm.l.Infof("sync once total closed connections: %d", cm.countClosedConnection()) + // todo: opt lock + cm.lock.Lock() + + shortCommit := constant.GitRevision + if len(constant.GitRevision) > 7 { + shortCommit = constant.GitRevision[:7] + } + req := syncReq{ + Stats: []StatsPerRule{}, + Version: VersionInfo{Version: constant.Version, ShortCommit: shortCommit}, + } + + if cm.cfg.NeedMetrics() { + metrics, err := cm.mr.ReadOnce(ctx) + if err != nil { + cm.l.Errorf("read metrics failed: %v", err) + } else { + req.Node = *metrics + if err := cm.ms.AddNodeMetric(metrics); err != nil { + cm.l.Errorf("add metrics to store failed: %v", err) + } + } + } + + for label, conns := range cm.closedConnectionsMap { + s := StatsPerRule{ + RelayLabel: label, + } + var totalLatency int64 + for _, c := range conns { + s.ConnectionCnt++ + s.Up += c.GetStats().Up + s.Down += c.GetStats().Down + totalLatency += c.GetStats().HandShakeLatency.Milliseconds() + } + if s.ConnectionCnt > 0 { + s.HandShakeLatency = totalLatency / int64(s.ConnectionCnt) + } + req.Stats = append(req.Stats, s) + } + cm.closedConnectionsMap = make(map[string][]conn.RelayConn) + cm.lock.Unlock() + + if cm.cfg.NeedSync() { + cm.l.Debug("syncing data to server", zap.Any("data", req)) + return myhttp.PostJSONWithRetry(cm.cfg.SyncURL, &req) + } else { + cm.l.Debugf("remove %d closed connections", len(req.Stats)) + } + return nil +} diff --git a/echo/internal/config/config.go b/echo/internal/config/config.go index abce8cc6bd..1c526583af 100644 --- a/echo/internal/config/config.go +++ b/echo/internal/config/config.go @@ -16,8 +16,9 @@ import ( ) type Config struct { - PATH string + PATH string `json:"-"` + NodeLabel string `json:"node_label,omitempty"` WebHost string `json:"web_host,omitempty"` WebPort int `json:"web_port,omitempty"` WebToken string `json:"web_token,omitempty"` @@ -105,7 +106,7 @@ func (c *Config) Adjust() error { } // init tls when need for _, r := range c.RelayConfigs { - if r.ListenType == constant.RelayTypeWSS { + if r.ListenType == constant.RelayTypeWSS || r.TransportType == constant.RelayTypeWSS { if err := tls.InitTlsCfg(); err != nil { return err } diff --git a/echo/internal/conn/relay_conn.go b/echo/internal/conn/relay_conn.go index cde0997d94..ed7d27733e 100644 --- a/echo/internal/conn/relay_conn.go +++ b/echo/internal/conn/relay_conn.go @@ -190,10 +190,10 @@ func (s *Stats) Record(up, down int64) { } func (s *Stats) String() string { - return fmt.Sprintf("up: %s, down: %s, handshake latency: %s", + return fmt.Sprintf("up: %s, down: %s, latency: %s", bytes.PrettyByteSize(float64(s.Up)), bytes.PrettyByteSize(float64(s.Down)), - s.HandShakeLatency.String(), + fmt.Sprintf("%d ms", s.HandShakeLatency.Milliseconds()), ) } diff --git a/echo/internal/relay/conf/cfg.go b/echo/internal/relay/conf/cfg.go index 11546bd5d3..862898ff50 100644 --- a/echo/internal/relay/conf/cfg.go +++ b/echo/internal/relay/conf/cfg.go @@ -49,10 +49,10 @@ type Options struct { SniffTimeoutSec int `json:"sniff_timeout_sec,omitempty"` // timeout in duration - DialTimeout time.Duration - IdleTimeout time.Duration - ReadTimeout time.Duration - SniffTimeout time.Duration + DialTimeout time.Duration `json:"-"` + IdleTimeout time.Duration `json:"-"` + ReadTimeout time.Duration `json:"-"` + SniffTimeout time.Duration `json:"-"` } func (o *Options) Clone() *Options { @@ -78,9 +78,6 @@ type Config struct { Remotes []string `json:"remotes"` Options *Options `json:"options,omitempty"` - - // deprecated - TCPRemotes []string `json:"tcp_remotes"` } func (r *Config) GetWSHandShakePath() string { @@ -106,10 +103,6 @@ func (r *Config) Adjust() error { r.Label = r.DefaultLabel() zap.S().Debugf("label is empty, set default label:%s", r.Label) } - if len(r.Remotes) == 0 && len(r.TCPRemotes) != 0 { - zap.S().Warnf("tcp remotes is deprecated, please use remotes instead") - r.Remotes = r.TCPRemotes - } if r.Options == nil { r.Options = newDefaultOptions() @@ -126,21 +119,17 @@ func (r *Config) Validate() error { if err := r.Adjust(); err != nil { return errors.New("adjust config failed") } - if err := r.validateType(); err != nil { return err } - if r.Listen == "" { return fmt.Errorf("invalid listen: %s", r.Listen) } - for _, addr := range r.Remotes { if addr == "" { return fmt.Errorf("invalid remote addr: %s", addr) } } - for _, protocol := range r.Options.BlockedProtocols { if protocol != ProtocolHTTP && protocol != ProtocolTLS { return fmt.Errorf("invalid blocked protocol: %s", protocol) @@ -227,10 +216,17 @@ func getDuration(seconds int, defaultDuration time.Duration) time.Duration { func newDefaultOptions() *Options { return &Options{ EnableMultipathTCP: true, - WSConfig: &WSConfig{}, - DialTimeout: constant.DefaultDialTimeOut, - IdleTimeout: constant.DefaultIdleTimeOut, - ReadTimeout: constant.DefaultReadTimeOut, - SniffTimeout: constant.DefaultSniffTimeOut, + + DialTimeout: constant.DefaultDialTimeOut, + DialTimeoutSec: int(constant.DefaultDialTimeOut.Seconds()), + + IdleTimeout: constant.DefaultIdleTimeOut, + IdleTimeoutSec: int(constant.DefaultIdleTimeOut.Seconds()), + + ReadTimeout: constant.DefaultReadTimeOut, + ReadTimeoutSec: int(constant.DefaultReadTimeOut.Seconds()), + + SniffTimeout: constant.DefaultSniffTimeOut, + SniffTimeoutSec: int(constant.DefaultSniffTimeOut.Seconds()), } } diff --git a/echo/internal/relay/server.go b/echo/internal/relay/server.go index 2681a78f56..7bb70f739f 100644 --- a/echo/internal/relay/server.go +++ b/echo/internal/relay/server.go @@ -35,13 +35,17 @@ func NewServer(cfg *config.Config) (*Server, error) { MetricsURL: cfg.GetMetricURL(), } cmgrCfg.Adjust() + cmgr, err := cmgr.NewCmgr(cmgrCfg) + if err != nil { + return nil, err + } s := &Server{ cfg: cfg, l: l, relayM: &sync.Map{}, errCH: make(chan error, 1), reloadCH: make(chan struct{}, 1), - Cmgr: cmgr.NewCmgr(cmgrCfg), + Cmgr: cmgr, } return s, nil } diff --git a/echo/internal/transporter/base.go b/echo/internal/transporter/base.go index 906b3d5eb6..bea3927fc4 100644 --- a/echo/internal/transporter/base.go +++ b/echo/internal/transporter/base.go @@ -89,6 +89,9 @@ func (b *BaseRelayServer) RelayUDPConn(ctx context.Context, c net.Conn, remote * } func (b *BaseRelayServer) checkConnectionLimit() error { + if b.cmgr == nil { + return nil + } if b.cfg.Options.MaxConnection > 0 && b.cmgr.CountConnection(cmgr.ConnectionTypeActive) >= b.cfg.Options.MaxConnection { return fmt.Errorf("relay:%s active connection count exceed limit %d", b.cfg.Label, b.cfg.Options.MaxConnection) } @@ -144,8 +147,11 @@ func (b *BaseRelayServer) handleRelayConn(c, rc net.Conn, remote *lb.Node, connT conn.WithHandshakeDuration(remote.HandShakeDuration), } relayConn := conn.NewRelayConn(c, rc, opts...) - b.cmgr.AddConnection(relayConn) - defer b.cmgr.RemoveConnection(relayConn) + if b.cmgr != nil { + b.cmgr.AddConnection(relayConn) + defer b.cmgr.RemoveConnection(relayConn) + } + return relayConn.Transport() } diff --git a/echo/internal/transporter/ws.go b/echo/internal/transporter/ws.go index 196c2e7cf0..fca4850e91 100644 --- a/echo/internal/transporter/ws.go +++ b/echo/internal/transporter/ws.go @@ -24,21 +24,19 @@ var ( ) type WsClient struct { - dialer *ws.Dialer - cfg *conf.Config - netDialer *net.Dialer - l *zap.SugaredLogger + dialer *ws.Dialer + cfg *conf.Config + l *zap.SugaredLogger } func newWsClient(cfg *conf.Config) (*WsClient, error) { s := &WsClient{ - cfg: cfg, - netDialer: NewNetDialer(cfg), - l: zap.S().Named(string(cfg.TransportType)), - dialer: &ws.DefaultDialer, // todo config buffer size - } - s.dialer.NetDial = func(ctx context.Context, network, addr string) (net.Conn, error) { - return s.netDialer.Dial(network, addr) + cfg: cfg, + l: zap.S().Named(string(cfg.TransportType)), + // todo config buffer size + dialer: &ws.Dialer{ + Timeout: cfg.Options.DialTimeout, + }, } return s, nil } @@ -64,7 +62,6 @@ func (s *WsClient) HandShake(ctx context.Context, remote *lb.Node, isTCP bool) ( if !isTCP { addr = s.addUDPQueryParam(addr) } - wsc, _, _, err := s.dialer.Dial(ctx, addr) if err != nil { return nil, err diff --git a/echo/internal/transporter/wss.go b/echo/internal/transporter/wss.go index dc157a6147..6c819de75b 100644 --- a/echo/internal/transporter/wss.go +++ b/echo/internal/transporter/wss.go @@ -24,6 +24,7 @@ func newWssClient(cfg *conf.Config) (*WssClient, error) { } // insert tls config wc.dialer.TLSConfig = mytls.DefaultTLSConfig + wc.dialer.TLSConfig.InsecureSkipVerify = true return &WssClient{WsClient: wc}, nil } @@ -44,6 +45,8 @@ func (s *WssServer) ListenAndServe(ctx context.Context) error { if err != nil { return err } + tlsCfg := mytls.DefaultTLSConfig + tlsCfg.InsecureSkipVerify = true tlsListener := tls.NewListener(listener, mytls.DefaultTLSConfig) return s.httpServer.Serve(tlsListener) } diff --git a/echo/internal/web/handlers.go b/echo/internal/web/handlers.go index 5b7521d927..dcd6a7d477 100644 --- a/echo/internal/web/handlers.go +++ b/echo/internal/web/handlers.go @@ -5,8 +5,10 @@ import ( "fmt" "net/http" "strconv" + "time" - "github.com/Ehco1996/ehco/internal/cmgr" + "github.com/Ehco1996/ehco/internal/cmgr/ms" + "github.com/Ehco1996/ehco/internal/config" "github.com/Ehco1996/ehco/internal/constant" "github.com/labstack/echo/v4" "go.uber.org/zap" @@ -28,12 +30,14 @@ func (s *Server) index(c echo.Context) error { GitRevision string BuildTime string StartTime string + Cfg config.Config }{ Version: constant.Version, GitBranch: constant.GitBranch, GitRevision: constant.GitRevision, BuildTime: constant.BuildTime, StartTime: constant.StartTime.Format("2006-01-02 15:04:05"), + Cfg: *s.cfg, } return c.Render(http.StatusOK, "index.html", data) } @@ -123,7 +127,23 @@ func (s *Server) ListRules(c echo.Context) error { } func (s *Server) GetNodeMetrics(c echo.Context) error { - req := &cmgr.QueryNodeMetricsReq{TimeRange: c.QueryParam("time_range")} + startTS := time.Now().Unix() - 60 + if c.QueryParam("start_ts") != "" { + star, err := strconv.ParseInt(c.QueryParam("start_ts"), 10, 64) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + } + startTS = star + } + endTS := time.Now().Unix() + if c.QueryParam("end_ts") != "" { + end, err := strconv.ParseInt(c.QueryParam("end_ts"), 10, 64) + if err != nil { + return echo.NewHTTPError(http.StatusBadRequest, err.Error()) + } + endTS = end + } + req := &ms.QueryNodeMetricsReq{StartTimestamp: startTS, EndTimestamp: endTS} latest := c.QueryParam("latest") if latest != "" { r, err := strconv.ParseBool(latest) diff --git a/echo/internal/web/server.go b/echo/internal/web/server.go index 18673a1e97..4efca1eab8 100644 --- a/echo/internal/web/server.go +++ b/echo/internal/web/server.go @@ -12,6 +12,7 @@ import ( "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus/promhttp" "go.uber.org/zap" @@ -24,6 +25,14 @@ import ( //go:embed templates/*.html var templatesFS embed.FS +const ( + metricsPath = "/metrics/" + indexPath = "/" + connectionsPath = "/connections/" + rulesPath = "/rules/" + apiPrefix = "/api/v1" +) + type Server struct { glue.Reloader glue.HealthChecker @@ -50,41 +59,25 @@ func NewServer( healthChecker glue.HealthChecker, connMgr cmgr.Cmgr, ) (*Server, error) { + if err := validateConfig(cfg); err != nil { + return nil, errors.Wrap(err, "invalid configuration") + } + l := zap.S().Named("web") - templates := template.Must(template.ParseFS(templatesFS, "templates/*.html")) - for _, temp := range templates.Templates() { - l.Debug("template name: ", temp.Name()) - } e := NewEchoServer() - e.Use(NginxLogMiddleware(l)) - e.Renderer = &echoTemplate{templates: templates} - if cfg.WebToken != "" { - e.Use(middleware.KeyAuthWithConfig(middleware.KeyAuthConfig{ - KeyLookup: "query:token", - Validator: func(key string, c echo.Context) (bool, error) { - return key == cfg.WebToken, nil - }, - })) + if err := setupMiddleware(e, cfg, l); err != nil { + return nil, errors.Wrap(err, "failed to setup middleware") } - if cfg.WebAuthUser != "" && cfg.WebAuthPass != "" { - e.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) { - // Be careful to use constant time comparison to prevent timing attacks - if subtle.ConstantTimeCompare([]byte(username), []byte(cfg.WebAuthUser)) == 1 && - subtle.ConstantTimeCompare([]byte(password), []byte(cfg.WebAuthPass)) == 1 { - return true, nil - } - return false, nil - })) + if err := setupTemplates(e, l); err != nil { + return nil, errors.Wrap(err, "failed to setup templates") } - if err := metrics.RegisterEhcoMetrics(cfg); err != nil { - return nil, err - } - if err := metrics.RegisterNodeExporterMetrics(cfg); err != nil { - return nil, err + if err := setupMetrics(cfg); err != nil { + return nil, errors.Wrap(err, "failed to setup metrics") } + s := &Server{ Reloader: relayReloader, HealthChecker: healthChecker, @@ -96,21 +89,87 @@ func NewServer( addr: net.JoinHostPort(cfg.WebHost, fmt.Sprintf("%d", cfg.WebPort)), } - // register handler - e.GET("/metrics/", echo.WrapHandler(promhttp.Handler())) + setupRoutes(s) + + return s, nil +} + +func validateConfig(cfg *config.Config) error { + // Add validation logic here + if cfg.WebPort <= 0 || cfg.WebPort > 65535 { + return errors.New("invalid web port") + } + // Add more validations as needed + return nil +} + +func setupMiddleware(e *echo.Echo, cfg *config.Config, l *zap.SugaredLogger) error { + e.Use(NginxLogMiddleware(l)) + + if cfg.WebToken != "" { + e.Use(middleware.KeyAuthWithConfig(middleware.KeyAuthConfig{ + KeyLookup: "query:token", + Validator: func(key string, c echo.Context) (bool, error) { + return key == cfg.WebToken, nil + }, + })) + } + + if cfg.WebAuthUser != "" && cfg.WebAuthPass != "" { + e.Use(middleware.BasicAuth(func(username, password string, c echo.Context) (bool, error) { + if subtle.ConstantTimeCompare([]byte(username), []byte(cfg.WebAuthUser)) == 1 && + subtle.ConstantTimeCompare([]byte(password), []byte(cfg.WebAuthPass)) == 1 { + return true, nil + } + return false, nil + })) + } + + return nil +} + +func setupTemplates(e *echo.Echo, l *zap.SugaredLogger) error { + funcMap := template.FuncMap{ + "sub": func(a, b int) int { return a - b }, + "add": func(a, b int) int { return a + b }, + } + tmpl, err := template.New("").Funcs(funcMap).ParseFS(templatesFS, "templates/*.html") + if err != nil { + return errors.Wrap(err, "failed to parse templates") + } + templates := template.Must(tmpl, nil) + for _, temp := range templates.Templates() { + l.Debug("template name: ", temp.Name()) + } + e.Renderer = &echoTemplate{templates: templates} + return nil +} + +func setupMetrics(cfg *config.Config) error { + if err := metrics.RegisterEhcoMetrics(cfg); err != nil { + return errors.Wrap(err, "failed to register Ehco metrics") + } + if err := metrics.RegisterNodeExporterMetrics(cfg); err != nil { + return errors.Wrap(err, "failed to register Node Exporter metrics") + } + return nil +} + +func setupRoutes(s *Server) { + e := s.e + + e.GET(metricsPath, echo.WrapHandler(promhttp.Handler())) e.GET("/debug/pprof/*", echo.WrapHandler(http.DefaultServeMux)) - e.GET("/", s.index) - e.GET("/connections/", s.ListConnections) - e.GET("/rules/", s.ListRules) + e.GET(indexPath, s.index) + e.GET(connectionsPath, s.ListConnections) + e.GET(rulesPath, s.ListRules) - // api group - api := e.Group("/api/v1") + api := e.Group(apiPrefix) api.GET("/config/", s.CurrentConfig) api.POST("/config/reload/", s.HandleReload) api.GET("/health_check/", s.HandleHealthCheck) api.GET("/node_metrics/", s.GetNodeMetrics) - return s, nil } func (s *Server) Start() error { diff --git a/echo/internal/web/templates/_head.html b/echo/internal/web/templates/_head.html new file mode 100644 index 0000000000..0e30406b1d --- /dev/null +++ b/echo/internal/web/templates/_head.html @@ -0,0 +1,13 @@ + + Ehco Web + + + + + + + + + + + diff --git a/echo/internal/web/templates/_metrics.html b/echo/internal/web/templates/_metrics.html new file mode 100644 index 0000000000..0e96f45508 --- /dev/null +++ b/echo/internal/web/templates/_metrics.html @@ -0,0 +1,374 @@ +
+
+

Node Metrics

+
+ + +
+
+
+
+
+
+ +
+
+ +
+
+ +
+ +
+ +
+
+
+
+ +
diff --git a/echo/internal/web/templates/_navbar.html b/echo/internal/web/templates/_navbar.html new file mode 100644 index 0000000000..fba5d64d36 --- /dev/null +++ b/echo/internal/web/templates/_navbar.html @@ -0,0 +1,58 @@ + +
diff --git a/echo/internal/web/templates/connection.html b/echo/internal/web/templates/connection.html index 6a66c4ec87..a932ae525c 100644 --- a/echo/internal/web/templates/connection.html +++ b/echo/internal/web/templates/connection.html @@ -1,33 +1,30 @@ - - - - - - - Connections - + {{template "_head.html" .}} + {{ template "_navbar.html" . }}
-

ALL Connections: {{.AllCount}}

+

Connections

+

Total: {{.AllCount}}

+ + {{if gt (len .ConnectionList) 0}}
- +
- + @@ -37,39 +34,70 @@ {{range .ConnectionList}} - - - - - + + + + + {{end}}
Relay LabelLabel Type Flow Stats
{{.RelayLabel}}{{.ConnType}}{{.GetFlow}}{{.Stats}}{{.GetTime}}{{.RelayLabel}}{{.ConnType}}{{.GetFlow}}{{.Stats}}{{.GetTime}}
{{else}} -
-

No connections available.

+
+

No {{.ConnType}} connections available.

{{end}} + + {{if gt .TotalPage 1}} + {{end}}
+ + + + diff --git a/echo/internal/web/templates/index.html b/echo/internal/web/templates/index.html index 9c01df9304..58b7e60ea2 100644 --- a/echo/internal/web/templates/index.html +++ b/echo/internal/web/templates/index.html @@ -1,108 +1,48 @@ - + - - Ehco Web - - - - - - - - - - + {{template "_head.html" .}} -
-
-
-

Ehco Relay

-
-
- -
-
-

Build Info

-
-
-
-
    -
  • Version: {{.Version}}
  • -
  • GitBranch: {{.GitBranch}}
  • -
  • GitRevision: {{.GitRevision}}
  • -
  • BuildTime: {{.BuildTime}}
  • -
  • StartTime: {{.StartTime}}
  • -
-
-
-
- -
-
-
+ {{ template "_navbar.html" . }} -
- -
-
-

Quick Links

-
- +
+
+
+
+
+

Build Info

+
+
+
+
    +
  • Version: {{.Version}}
  • +
  • GitBranch: {{.GitBranch}}
  • +
  • GitRevision: {{.GitRevision}}
  • +
  • BuildTime: {{.BuildTime}}
  • +
  • StartTime: {{.StartTime}}
  • +
+
+ +
- - {{template "metrics.html"}}
+ + {{template "_metrics.html" .}} +
- -
- -
-
+ +
+ +
- diff --git a/echo/internal/web/templates/rule_list.html b/echo/internal/web/templates/rule_list.html index 3881f56208..bebf6e18c1 100644 --- a/echo/internal/web/templates/rule_list.html +++ b/echo/internal/web/templates/rule_list.html @@ -1,18 +1,11 @@ - + - - - - - - - - Rules - + {{template "_head.html" .}} + {{ template "_navbar.html" . }}
-

Rules

+

Rules

@@ -60,7 +53,7 @@ response.msg + // Use 'msg' as per Go struct ' (Latency: ' + response.latency + // Ensure this matches the Go struct field name - 'ms)' + 'ms)', ); } else { // If error code is not 0, show error message diff --git a/echo/test/relay_test.go b/echo/test/relay_test.go index 487ba36e4b..2e62401051 100644 --- a/echo/test/relay_test.go +++ b/echo/test/relay_test.go @@ -8,7 +8,6 @@ import ( "testing" "time" - "github.com/Ehco1996/ehco/internal/cmgr" "github.com/Ehco1996/ehco/internal/config" "github.com/Ehco1996/ehco/internal/constant" @@ -121,7 +120,7 @@ func startRelayServers() []*relay.Relay { var servers []*relay.Relay for _, c := range cfg.RelayConfigs { c.Adjust() - r, err := relay.NewRelay(c, cmgr.NewCmgr(cmgr.DummyConfig)) + r, err := relay.NewRelay(c, nil) if err != nil { zap.S().Fatal(err) } diff --git a/mieru/pkg/appctl/appctlpb/base.pb.go b/mieru/pkg/appctl/appctlpb/base.pb.go index d21f84ae3f..af841d0795 100644 --- a/mieru/pkg/appctl/appctlpb/base.pb.go +++ b/mieru/pkg/appctl/appctlpb/base.pb.go @@ -562,6 +562,63 @@ func (x *Quota) GetMegabytes() int32 { return 0 } +type Auth struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Username used for authentication. + User *string `protobuf:"bytes,1,opt,name=user,proto3,oneof" json:"user,omitempty"` + // Password used for authentication. + Password *string `protobuf:"bytes,2,opt,name=password,proto3,oneof" json:"password,omitempty"` +} + +func (x *Auth) Reset() { + *x = Auth{} + if protoimpl.UnsafeEnabled { + mi := &file_base_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Auth) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Auth) ProtoMessage() {} + +func (x *Auth) ProtoReflect() protoreflect.Message { + mi := &file_base_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Auth.ProtoReflect.Descriptor instead. +func (*Auth) Descriptor() ([]byte, []int) { + return file_base_proto_rawDescGZIP(), []int{6} +} + +func (x *Auth) GetUser() string { + if x != nil && x.User != nil { + return *x.User + } + return "" +} + +func (x *Auth) GetPassword() string { + if x != nil && x.Password != nil { + return *x.Password + } + return "" +} + var File_base_proto protoreflect.FileDescriptor var file_base_proto_rawDesc = []byte{ @@ -611,25 +668,31 @@ var file_base_proto_rawDesc = []byte{ 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x48, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x67, 0x61, 0x62, 0x79, 0x74, 0x65, 0x73, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x64, 0x61, 0x79, 0x73, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x65, 0x67, 0x61, 0x62, 0x79, 0x74, 0x65, - 0x73, 0x2a, 0x4b, 0x0a, 0x09, 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, - 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x49, - 0x44, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e, - 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x03, - 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x4f, 0x50, 0x50, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x2a, 0x5b, - 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x0b, - 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x46, - 0x41, 0x54, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, - 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x49, - 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x05, - 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x06, 0x2a, 0x45, 0x0a, 0x11, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x12, 0x1e, 0x0a, 0x1a, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x52, 0x41, 0x4e, - 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x00, - 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, - 0x10, 0x02, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x65, 0x6e, 0x66, 0x65, 0x69, 0x6e, 0x2f, 0x6d, 0x69, 0x65, 0x72, 0x75, 0x2f, 0x70, 0x6b, - 0x67, 0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x70, - 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x22, 0x56, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x12, 0x17, 0x0a, 0x04, 0x75, 0x73, 0x65, + 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x88, + 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x42, 0x0b, 0x0a, 0x09, + 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x2a, 0x4b, 0x0a, 0x09, 0x41, 0x70, 0x70, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x44, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a, + 0x08, 0x53, 0x54, 0x41, 0x52, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x52, + 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x54, 0x4f, 0x50, + 0x50, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x2a, 0x5b, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x67, 0x69, 0x6e, + 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, + 0x54, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x09, + 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, + 0x4e, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x04, 0x12, 0x09, 0x0a, + 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, + 0x45, 0x10, 0x06, 0x2a, 0x45, 0x0a, 0x11, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1e, 0x0a, 0x1a, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x5f, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x50, 0x52, + 0x4f, 0x54, 0x4f, 0x43, 0x4f, 0x4c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x55, 0x44, 0x50, 0x10, + 0x01, 0x12, 0x07, 0x0a, 0x03, 0x54, 0x43, 0x50, 0x10, 0x02, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6e, 0x66, 0x65, 0x69, 0x6e, 0x2f, + 0x6d, 0x69, 0x65, 0x72, 0x75, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, + 0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -645,7 +708,7 @@ func file_base_proto_rawDescGZIP() []byte { } var file_base_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_base_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_base_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_base_proto_goTypes = []interface{}{ (AppStatus)(0), // 0: appctl.AppStatus (LoggingLevel)(0), // 1: appctl.LoggingLevel @@ -656,6 +719,7 @@ var file_base_proto_goTypes = []interface{}{ (*PortBinding)(nil), // 6: appctl.PortBinding (*User)(nil), // 7: appctl.User (*Quota)(nil), // 8: appctl.Quota + (*Auth)(nil), // 9: appctl.Auth } var file_base_proto_depIdxs = []int32{ 0, // 0: appctl.AppStatusMsg.status:type_name -> appctl.AppStatus @@ -747,19 +811,32 @@ func file_base_proto_init() { return nil } } + file_base_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Auth); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_base_proto_msgTypes[1].OneofWrappers = []interface{}{} file_base_proto_msgTypes[2].OneofWrappers = []interface{}{} file_base_proto_msgTypes[3].OneofWrappers = []interface{}{} file_base_proto_msgTypes[4].OneofWrappers = []interface{}{} file_base_proto_msgTypes[5].OneofWrappers = []interface{}{} + file_base_proto_msgTypes[6].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_base_proto_rawDesc, NumEnums: 3, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/mieru/pkg/appctl/appctlpb/clientcfg.pb.go b/mieru/pkg/appctl/appctlpb/clientcfg.pb.go index 4d6106ae82..13f305375d 100644 --- a/mieru/pkg/appctl/appctlpb/clientcfg.pb.go +++ b/mieru/pkg/appctl/appctlpb/clientcfg.pb.go @@ -113,6 +113,9 @@ type ClientConfig struct { HttpProxyPort *int32 `protobuf:"varint,8,opt,name=httpProxyPort,proto3,oneof" json:"httpProxyPort,omitempty"` // If set, the HTTP proxy port listens to LAN rather than localhost. HttpProxyListenLAN *bool `protobuf:"varint,9,opt,name=httpProxyListenLAN,proto3,oneof" json:"httpProxyListenLAN,omitempty"` + // A list of accounts that can authenticate mieru socks5 proxy service. + // If the list is empty, authentication is not required. + Socks5Authentication []*Auth `protobuf:"bytes,10,rep,name=socks5Authentication,proto3" json:"socks5Authentication,omitempty"` } func (x *ClientConfig) Reset() { @@ -210,6 +213,13 @@ func (x *ClientConfig) GetHttpProxyListenLAN() bool { return false } +func (x *ClientConfig) GetSocks5Authentication() []*Auth { + if x != nil { + return x.Socks5Authentication + } + return nil +} + type ClientProfile struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -386,7 +396,7 @@ var File_clientcfg_proto protoreflect.FileDescriptor var file_clientcfg_proto_rawDesc = []byte{ 0x0a, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x63, 0x66, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x1a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xdf, 0x04, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa1, 0x05, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, @@ -415,53 +425,57 @@ var file_clientcfg_proto_rawDesc = []byte{ 0x01, 0x01, 0x12, 0x33, 0x0a, 0x12, 0x68, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x4c, 0x41, 0x4e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x48, 0x07, 0x52, 0x12, 0x68, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x65, - 0x6e, 0x4c, 0x41, 0x4e, 0x88, 0x01, 0x01, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x61, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x72, 0x70, - 0x63, 0x50, 0x6f, 0x72, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x35, - 0x50, 0x6f, 0x72, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, - 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x6c, 0x6f, - 0x67, 0x67, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x12, 0x0a, 0x10, 0x5f, 0x73, - 0x6f, 0x63, 0x6b, 0x73, 0x35, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x4c, 0x41, 0x4e, 0x42, 0x10, - 0x0a, 0x0e, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x6f, 0x72, 0x74, - 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x4c, 0x69, - 0x73, 0x74, 0x65, 0x6e, 0x4c, 0x41, 0x4e, 0x22, 0x9d, 0x02, 0x0a, 0x0d, 0x43, 0x6c, 0x69, 0x65, - 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x25, 0x0a, 0x0b, 0x70, 0x72, 0x6f, - 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, - 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, - 0x12, 0x25, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, - 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x48, 0x01, 0x52, 0x04, - 0x75, 0x73, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, - 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x15, 0x0a, 0x03, 0x6d, 0x74, 0x75, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, 0x02, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x88, 0x01, 0x01, - 0x12, 0x43, 0x0a, 0x0c, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, - 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x48, 0x03, 0x52, 0x0c, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, - 0x6e, 0x67, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, - 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x42, 0x06, - 0x0a, 0x04, 0x5f, 0x6d, 0x74, 0x75, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, - 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x22, 0x54, 0x0a, 0x12, 0x4d, 0x75, 0x6c, 0x74, 0x69, - 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, - 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x61, - 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, - 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x48, 0x00, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, - 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x18, 0x0a, - 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x53, - 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2a, 0x89, 0x01, 0x0a, 0x11, 0x4d, 0x75, 0x6c, 0x74, - 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x18, 0x0a, - 0x14, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x58, 0x49, 0x4e, 0x47, 0x5f, 0x44, 0x45, - 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x4d, 0x55, 0x4c, 0x54, 0x49, - 0x50, 0x4c, 0x45, 0x58, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x46, 0x46, 0x10, 0x01, 0x12, 0x14, 0x0a, - 0x10, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x58, 0x49, 0x4e, 0x47, 0x5f, 0x4c, 0x4f, - 0x57, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x58, - 0x49, 0x4e, 0x47, 0x5f, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x15, 0x0a, 0x11, - 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x58, 0x49, 0x4e, 0x47, 0x5f, 0x48, 0x49, 0x47, - 0x48, 0x10, 0x04, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x65, 0x6e, 0x66, 0x65, 0x69, 0x6e, 0x2f, 0x6d, 0x69, 0x65, 0x72, 0x75, 0x2f, 0x70, - 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, - 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6e, 0x4c, 0x41, 0x4e, 0x88, 0x01, 0x01, 0x12, 0x40, 0x0a, 0x14, 0x73, 0x6f, 0x63, 0x6b, 0x73, + 0x35, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x41, + 0x75, 0x74, 0x68, 0x52, 0x14, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x35, 0x41, 0x75, 0x74, 0x68, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, + 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, 0x6f, 0x63, 0x6b, + 0x73, 0x35, 0x50, 0x6f, 0x72, 0x74, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x61, 0x64, 0x76, 0x61, 0x6e, + 0x63, 0x65, 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, + 0x6c, 0x6f, 0x67, 0x67, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x42, 0x12, 0x0a, 0x10, + 0x5f, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x35, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x4c, 0x41, 0x4e, + 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x50, 0x6f, + 0x72, 0x74, 0x42, 0x15, 0x0a, 0x13, 0x5f, 0x68, 0x74, 0x74, 0x70, 0x50, 0x72, 0x6f, 0x78, 0x79, + 0x4c, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x4c, 0x41, 0x4e, 0x22, 0x9d, 0x02, 0x0a, 0x0d, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x25, 0x0a, 0x0b, 0x70, + 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x00, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x88, + 0x01, 0x01, 0x12, 0x25, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0c, 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x48, 0x01, + 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x88, 0x01, 0x01, 0x12, 0x30, 0x0a, 0x07, 0x73, 0x65, 0x72, + 0x76, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x61, 0x70, 0x70, + 0x63, 0x74, 0x6c, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, + 0x6e, 0x74, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x15, 0x0a, 0x03, 0x6d, + 0x74, 0x75, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, 0x02, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x88, + 0x01, 0x01, 0x12, 0x43, 0x0a, 0x0c, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, + 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, + 0x6c, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x48, 0x03, 0x52, 0x0c, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, + 0x78, 0x69, 0x6e, 0x67, 0x88, 0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x70, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x75, 0x73, 0x65, 0x72, + 0x42, 0x06, 0x0a, 0x04, 0x5f, 0x6d, 0x74, 0x75, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x6d, 0x75, 0x6c, + 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x22, 0x54, 0x0a, 0x12, 0x4d, 0x75, 0x6c, + 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x34, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, + 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, + 0x78, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x48, 0x00, 0x52, 0x05, 0x6c, 0x65, 0x76, + 0x65, 0x6c, 0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x22, + 0x18, 0x0a, 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, + 0x64, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x2a, 0x89, 0x01, 0x0a, 0x11, 0x4d, 0x75, + 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x78, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, + 0x18, 0x0a, 0x14, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x58, 0x49, 0x4e, 0x47, 0x5f, + 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x4d, 0x55, 0x4c, + 0x54, 0x49, 0x50, 0x4c, 0x45, 0x58, 0x49, 0x4e, 0x47, 0x5f, 0x4f, 0x46, 0x46, 0x10, 0x01, 0x12, + 0x14, 0x0a, 0x10, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x58, 0x49, 0x4e, 0x47, 0x5f, + 0x4c, 0x4f, 0x57, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, + 0x45, 0x58, 0x49, 0x4e, 0x47, 0x5f, 0x4d, 0x49, 0x44, 0x44, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x15, + 0x0a, 0x11, 0x4d, 0x55, 0x4c, 0x54, 0x49, 0x50, 0x4c, 0x45, 0x58, 0x49, 0x4e, 0x47, 0x5f, 0x48, + 0x49, 0x47, 0x48, 0x10, 0x04, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x6e, 0x66, 0x65, 0x69, 0x6e, 0x2f, 0x6d, 0x69, 0x65, 0x72, 0x75, + 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2f, 0x61, 0x70, 0x70, 0x63, + 0x74, 0x6c, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -485,22 +499,24 @@ var file_clientcfg_proto_goTypes = []interface{}{ (*MultiplexingConfig)(nil), // 3: appctl.MultiplexingConfig (*ClientAdvancedSettings)(nil), // 4: appctl.ClientAdvancedSettings (LoggingLevel)(0), // 5: appctl.LoggingLevel - (*User)(nil), // 6: appctl.User - (*ServerEndpoint)(nil), // 7: appctl.ServerEndpoint + (*Auth)(nil), // 6: appctl.Auth + (*User)(nil), // 7: appctl.User + (*ServerEndpoint)(nil), // 8: appctl.ServerEndpoint } var file_clientcfg_proto_depIdxs = []int32{ 2, // 0: appctl.ClientConfig.profiles:type_name -> appctl.ClientProfile 4, // 1: appctl.ClientConfig.advancedSettings:type_name -> appctl.ClientAdvancedSettings 5, // 2: appctl.ClientConfig.loggingLevel:type_name -> appctl.LoggingLevel - 6, // 3: appctl.ClientProfile.user:type_name -> appctl.User - 7, // 4: appctl.ClientProfile.servers:type_name -> appctl.ServerEndpoint - 3, // 5: appctl.ClientProfile.multiplexing:type_name -> appctl.MultiplexingConfig - 0, // 6: appctl.MultiplexingConfig.level:type_name -> appctl.MultiplexingLevel - 7, // [7:7] is the sub-list for method output_type - 7, // [7:7] is the sub-list for method input_type - 7, // [7:7] is the sub-list for extension type_name - 7, // [7:7] is the sub-list for extension extendee - 0, // [0:7] is the sub-list for field type_name + 6, // 3: appctl.ClientConfig.socks5Authentication:type_name -> appctl.Auth + 7, // 4: appctl.ClientProfile.user:type_name -> appctl.User + 8, // 5: appctl.ClientProfile.servers:type_name -> appctl.ServerEndpoint + 3, // 6: appctl.ClientProfile.multiplexing:type_name -> appctl.MultiplexingConfig + 0, // 7: appctl.MultiplexingConfig.level:type_name -> appctl.MultiplexingLevel + 8, // [8:8] is the sub-list for method output_type + 8, // [8:8] is the sub-list for method input_type + 8, // [8:8] is the sub-list for extension type_name + 8, // [8:8] is the sub-list for extension extendee + 0, // [0:8] is the sub-list for field type_name } func init() { file_clientcfg_proto_init() } diff --git a/mieru/pkg/appctl/appctlpb/servercfg.pb.go b/mieru/pkg/appctl/appctlpb/servercfg.pb.go index 7ef113ca99..77debaa15a 100644 --- a/mieru/pkg/appctl/appctlpb/servercfg.pb.go +++ b/mieru/pkg/appctl/appctlpb/servercfg.pb.go @@ -345,6 +345,9 @@ type EgressProxy struct { Host *string `protobuf:"bytes,3,opt,name=host,proto3,oneof" json:"host,omitempty"` // Proxy port number. Port *int32 `protobuf:"varint,4,opt,name=port,proto3,oneof" json:"port,omitempty"` + // Credential to authenticate egress socks5 proxy. + // If the proxy protocol is not socks5, this is ignored. + Socks5Authentication *Auth `protobuf:"bytes,5,opt,name=socks5Authentication,proto3,oneof" json:"socks5Authentication,omitempty"` } func (x *EgressProxy) Reset() { @@ -407,6 +410,13 @@ func (x *EgressProxy) GetPort() int32 { return 0 } +func (x *EgressProxy) GetSocks5Authentication() *Auth { + if x != nil { + return x.Socks5Authentication + } + return nil +} + type EgressRule struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -527,7 +537,7 @@ var file_servercfg_proto_rawDesc = []byte{ 0x07, 0x70, 0x72, 0x6f, 0x78, 0x69, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, - 0x65, 0x73, 0x22, 0xb8, 0x01, 0x0a, 0x0b, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, + 0x65, 0x73, 0x22, 0x98, 0x02, 0x0a, 0x0b, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x12, 0x17, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, @@ -536,9 +546,15 @@ var file_servercfg_proto_rawDesc = []byte{ 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x02, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x88, 0x01, 0x01, 0x12, 0x17, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x48, 0x03, 0x52, 0x04, 0x70, 0x6f, - 0x72, 0x74, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0b, - 0x0a, 0x09, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x42, 0x07, 0x0a, 0x05, 0x5f, - 0x68, 0x6f, 0x73, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x22, 0xb9, 0x01, + 0x72, 0x74, 0x88, 0x01, 0x01, 0x12, 0x45, 0x0a, 0x14, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x35, 0x41, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x61, 0x70, 0x70, 0x63, 0x74, 0x6c, 0x2e, 0x41, 0x75, 0x74, + 0x68, 0x48, 0x04, 0x52, 0x14, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x35, 0x41, 0x75, 0x74, 0x68, 0x65, + 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x5f, + 0x70, 0x6f, 0x72, 0x74, 0x42, 0x17, 0x0a, 0x15, 0x5f, 0x73, 0x6f, 0x63, 0x6b, 0x73, 0x35, 0x41, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb9, 0x01, 0x0a, 0x0a, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x70, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x69, 0x70, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x6f, 0x6d, 0x61, @@ -589,22 +605,24 @@ var file_servercfg_proto_goTypes = []interface{}{ (*PortBinding)(nil), // 7: appctl.PortBinding (*User)(nil), // 8: appctl.User (LoggingLevel)(0), // 9: appctl.LoggingLevel + (*Auth)(nil), // 10: appctl.Auth } var file_servercfg_proto_depIdxs = []int32{ - 7, // 0: appctl.ServerConfig.portBindings:type_name -> appctl.PortBinding - 8, // 1: appctl.ServerConfig.users:type_name -> appctl.User - 3, // 2: appctl.ServerConfig.advancedSettings:type_name -> appctl.ServerAdvancedSettings - 9, // 3: appctl.ServerConfig.loggingLevel:type_name -> appctl.LoggingLevel - 4, // 4: appctl.ServerConfig.egress:type_name -> appctl.Egress - 5, // 5: appctl.Egress.proxies:type_name -> appctl.EgressProxy - 6, // 6: appctl.Egress.rules:type_name -> appctl.EgressRule - 0, // 7: appctl.EgressProxy.protocol:type_name -> appctl.ProxyProtocol - 1, // 8: appctl.EgressRule.action:type_name -> appctl.EgressAction - 9, // [9:9] is the sub-list for method output_type - 9, // [9:9] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 7, // 0: appctl.ServerConfig.portBindings:type_name -> appctl.PortBinding + 8, // 1: appctl.ServerConfig.users:type_name -> appctl.User + 3, // 2: appctl.ServerConfig.advancedSettings:type_name -> appctl.ServerAdvancedSettings + 9, // 3: appctl.ServerConfig.loggingLevel:type_name -> appctl.LoggingLevel + 4, // 4: appctl.ServerConfig.egress:type_name -> appctl.Egress + 5, // 5: appctl.Egress.proxies:type_name -> appctl.EgressProxy + 6, // 6: appctl.Egress.rules:type_name -> appctl.EgressRule + 0, // 7: appctl.EgressProxy.protocol:type_name -> appctl.ProxyProtocol + 10, // 8: appctl.EgressProxy.socks5Authentication:type_name -> appctl.Auth + 1, // 9: appctl.EgressRule.action:type_name -> appctl.EgressAction + 10, // [10:10] is the sub-list for method output_type + 10, // [10:10] is the sub-list for method input_type + 10, // [10:10] is the sub-list for extension type_name + 10, // [10:10] is the sub-list for extension extendee + 0, // [0:10] is the sub-list for field type_name } func init() { file_servercfg_proto_init() } diff --git a/mieru/pkg/appctl/client.go b/mieru/pkg/appctl/client.go index 3ffbafbcce..9cf8263438 100644 --- a/mieru/pkg/appctl/client.go +++ b/mieru/pkg/appctl/client.go @@ -361,6 +361,7 @@ func DeleteClientConfigProfile(profileName string) error { // 2.5.2. if set, server's IP address is parsable // 2.5.3. the server has at least 1 port binding, and all port bindings are valid // 2.6. if set, MTU is valid +// 3. for each socks5 authentication, the user and password are not empty func ValidateClientConfigPatch(patch *pb.ClientConfig) error { for _, profile := range patch.GetProfiles() { name := profile.GetProfileName() @@ -400,6 +401,14 @@ func ValidateClientConfigPatch(patch *pb.ClientConfig) error { return fmt.Errorf("MTU value %d is out of range, valid range is [1280, 1500]", profile.GetMtu()) } } + for _, auth := range patch.GetSocks5Authentication() { + if auth.GetUser() == "" { + return fmt.Errorf("socks5 authentication user is not set") + } + if auth.GetPassword() == "" { + return fmt.Errorf("socks5 authentication password is not set") + } + } return nil } @@ -606,6 +615,10 @@ func mergeClientConfigByProfile(dst, src *pb.ClientConfig) { if src.HttpProxyListenLAN != nil { httpProxyListenLAN = src.HttpProxyListenLAN } + var socks5Authentication []*pb.Auth = dst.Socks5Authentication + if src.Socks5Authentication != nil { + socks5Authentication = src.Socks5Authentication + } proto.Reset(dst) @@ -619,6 +632,7 @@ func mergeClientConfigByProfile(dst, src *pb.ClientConfig) { dst.Socks5ListenLAN = socks5ListenLAN dst.HttpProxyPort = httpProxyPort dst.HttpProxyListenLAN = httpProxyListenLAN + dst.Socks5Authentication = socks5Authentication } // deleteClientConfigFile deletes the client config file. diff --git a/mieru/pkg/appctl/client_test.go b/mieru/pkg/appctl/client_test.go index 0764aeb3f7..2fba42d036 100644 --- a/mieru/pkg/appctl/client_test.go +++ b/mieru/pkg/appctl/client_test.go @@ -67,6 +67,7 @@ func TestApply2ClientConfig(t *testing.T) { func TestClientApplyReject(t *testing.T) { cases := []string{ "testdata/client_reject_active_profile_mismatch.json", + "testdata/client_reject_invalid_http_port.json", "testdata/client_reject_invalid_rpc_port.json", "testdata/client_reject_mtu_too_big.json", "testdata/client_reject_mtu_too_small.json", @@ -75,13 +76,17 @@ func TestClientApplyReject(t *testing.T) { "testdata/client_reject_no_port_binding.json", "testdata/client_reject_no_port.json", "testdata/client_reject_no_profile_name.json", + "testdata/client_reject_no_profiles.json", "testdata/client_reject_no_protocol.json", "testdata/client_reject_no_server_addr.json", + "testdata/client_reject_no_servers.json", "testdata/client_reject_no_socks5_port.json", "testdata/client_reject_no_user_name.json", "testdata/client_reject_same_port_http_rpc.json", "testdata/client_reject_same_port_http_socks5.json", "testdata/client_reject_same_port_rpc_socks5.json", + "testdata/client_reject_socks5_auth_no_password.json", + "testdata/client_reject_socks5_auth_no_user.json", "testdata/client_reject_user_has_quota.json", "testdata/client_reject_wrong_ipv4_address.json", "testdata/client_reject_wrong_ipv6_address.json", diff --git a/mieru/pkg/appctl/proto/base.proto b/mieru/pkg/appctl/proto/base.proto index 10e41c3493..bac7536d62 100644 --- a/mieru/pkg/appctl/proto/base.proto +++ b/mieru/pkg/appctl/proto/base.proto @@ -111,3 +111,12 @@ message Quota { // Number of megabytes the user allowed to send and receive. optional int32 megabytes = 2; } + +message Auth { + + // Username used for authentication. + optional string user = 1; + + // Password used for authentication. + optional string password = 2; +} diff --git a/mieru/pkg/appctl/proto/clientcfg.proto b/mieru/pkg/appctl/proto/clientcfg.proto index 5c3d921c12..8f6c39ff49 100644 --- a/mieru/pkg/appctl/proto/clientcfg.proto +++ b/mieru/pkg/appctl/proto/clientcfg.proto @@ -48,6 +48,10 @@ message ClientConfig { // If set, the HTTP proxy port listens to LAN rather than localhost. optional bool httpProxyListenLAN = 9; + + // A list of accounts that can authenticate mieru socks5 proxy service. + // If the list is empty, authentication is not required. + repeated Auth socks5Authentication = 10; } message ClientProfile { diff --git a/mieru/pkg/appctl/proto/servercfg.proto b/mieru/pkg/appctl/proto/servercfg.proto index 5c32df8903..4dd7c0a735 100644 --- a/mieru/pkg/appctl/proto/servercfg.proto +++ b/mieru/pkg/appctl/proto/servercfg.proto @@ -67,6 +67,10 @@ message EgressProxy { // Proxy port number. optional int32 port = 4; + + // Credential to authenticate egress socks5 proxy. + // If the proxy protocol is not socks5, this is ignored. + optional Auth socks5Authentication = 5; } enum ProxyProtocol { diff --git a/mieru/pkg/appctl/server.go b/mieru/pkg/appctl/server.go index 9ccdb12c4e..1a0cb70701 100644 --- a/mieru/pkg/appctl/server.go +++ b/mieru/pkg/appctl/server.go @@ -544,6 +544,7 @@ func DeleteServerUsers(names []string) error { // 4.3. protocol is valid // 4.4. host is not empty // 4.5. port is valid +// 4.6. if socks5 authentication is used, the user and password are not empty // 5. there is maximum 1 egress rule // 5.1. the IP ranges must be "*" // 5.2. the domain names must be "*" @@ -590,6 +591,14 @@ func ValidateServerConfigPatch(patch *pb.ServerConfig) error { if proxy.GetPort() < 1 || proxy.GetPort() > 65535 { return fmt.Errorf("egress proxy port number %d is invalid", proxy.GetPort()) } + hasSocks5AuthenticationUser := proxy.GetSocks5Authentication().GetUser() != "" + hasSocks5AuthenticationPassword := proxy.GetSocks5Authentication().GetPassword() != "" + if !hasSocks5AuthenticationUser && hasSocks5AuthenticationPassword { + return fmt.Errorf("egress proxy socks5 authentication user is not set") + } + if hasSocks5AuthenticationUser && !hasSocks5AuthenticationPassword { + return fmt.Errorf("egress proxy socks5 authentication password is not set") + } } if len(patch.GetEgress().GetRules()) > 1 { return fmt.Errorf("found %d egress rules, maximum number of supported rules is 1", len(patch.GetEgress().GetRules())) diff --git a/mieru/pkg/appctl/testdata/client_apply_config_1.json b/mieru/pkg/appctl/testdata/client_apply_config_1.json index 2e573af6bb..7cdbc552f3 100644 --- a/mieru/pkg/appctl/testdata/client_apply_config_1.json +++ b/mieru/pkg/appctl/testdata/client_apply_config_1.json @@ -27,5 +27,6 @@ "rpcPort": 1989, "socks5Port": 1080, "loggingLevel": "DEBUG", - "socks5ListenLAN": true + "socks5ListenLAN": true, + "socks5Authentication": [] } diff --git a/mieru/pkg/appctl/testdata/client_apply_config_2.json b/mieru/pkg/appctl/testdata/client_apply_config_2.json index 4eb7328b5b..a3ebabd5ed 100644 --- a/mieru/pkg/appctl/testdata/client_apply_config_2.json +++ b/mieru/pkg/appctl/testdata/client_apply_config_2.json @@ -68,5 +68,11 @@ "loggingLevel": "INFO", "socks5ListenLAN": false, "httpProxyPort": 8080, - "httpProxyListenLAN": true + "httpProxyListenLAN": true, + "socks5Authentication": [ + { + "user": "shilishanlu", + "password": "buhuanjian" + } + ] } diff --git a/mieru/pkg/appctl/testdata/client_reject_invalid_http_port.json b/mieru/pkg/appctl/testdata/client_reject_invalid_http_port.json new file mode 100644 index 0000000000..b82f22e4f7 --- /dev/null +++ b/mieru/pkg/appctl/testdata/client_reject_invalid_http_port.json @@ -0,0 +1,26 @@ +{ + "profiles": [ + { + "profileName": "default", + "user": { + "name": "user1", + "password": "fa7206ed2a94" + }, + "servers": [ + { + "ipAddress": "1.1.1.1", + "portBindings": [ + { + "port": 4000, + "protocol": "UDP" + } + ] + } + ] + } + ], + "activeProfile": "default", + "rpcPort": 1989, + "socks5Port": 1080, + "httpProxyPort": 1000000 +} diff --git a/mieru/pkg/appctl/testdata/client_reject_no_profiles.json b/mieru/pkg/appctl/testdata/client_reject_no_profiles.json new file mode 100644 index 0000000000..4bd2261218 --- /dev/null +++ b/mieru/pkg/appctl/testdata/client_reject_no_profiles.json @@ -0,0 +1,5 @@ +{ + "activeProfile": "default", + "rpcPort": 1989, + "socks5Port": 1080 +} diff --git a/mieru/pkg/appctl/testdata/client_reject_no_servers.json b/mieru/pkg/appctl/testdata/client_reject_no_servers.json new file mode 100644 index 0000000000..5b61ef794f --- /dev/null +++ b/mieru/pkg/appctl/testdata/client_reject_no_servers.json @@ -0,0 +1,14 @@ +{ + "profiles": [ + { + "profileName": "default", + "user": { + "name": "user1", + "password": "fa7206ed2a94" + } + } + ], + "activeProfile": "default", + "rpcPort": 1989, + "socks5Port": 1080 +} diff --git a/mieru/pkg/appctl/testdata/client_reject_socks5_auth_no_password.json b/mieru/pkg/appctl/testdata/client_reject_socks5_auth_no_password.json new file mode 100644 index 0000000000..be1042d581 --- /dev/null +++ b/mieru/pkg/appctl/testdata/client_reject_socks5_auth_no_password.json @@ -0,0 +1,34 @@ +{ + "profiles": [ + { + "profileName": "default", + "user": { + "name": "user1", + "password": "fa7206ed2a94" + }, + "servers": [ + { + "ipAddress": "1.1.1.1", + "portBindings": [ + { + "port": 4000, + "protocol": "UDP" + } + ] + } + ] + } + ], + "activeProfile": "default", + "rpcPort": 1989, + "socks5Port": 1080, + "socks5Authentication": [ + { + "user": "shilishanlu", + "password": "buhuanjian" + }, + { + "user": "yitukai" + } + ] +} diff --git a/mieru/pkg/appctl/testdata/client_reject_socks5_auth_no_user.json b/mieru/pkg/appctl/testdata/client_reject_socks5_auth_no_user.json new file mode 100644 index 0000000000..320851e962 --- /dev/null +++ b/mieru/pkg/appctl/testdata/client_reject_socks5_auth_no_user.json @@ -0,0 +1,34 @@ +{ + "profiles": [ + { + "profileName": "default", + "user": { + "name": "user1", + "password": "fa7206ed2a94" + }, + "servers": [ + { + "ipAddress": "1.1.1.1", + "portBindings": [ + { + "port": 4000, + "protocol": "UDP" + } + ] + } + ] + } + ], + "activeProfile": "default", + "rpcPort": 1989, + "socks5Port": 1080, + "socks5Authentication": [ + { + "user": "shilishanlu", + "password": "buhuanjian" + }, + { + "password": "manlianpenfen" + } + ] +} diff --git a/openwrt-packages/UnblockNeteaseMusic/Makefile b/openwrt-packages/UnblockNeteaseMusic/Makefile index 256576ed27..6184e6b82d 100644 --- a/openwrt-packages/UnblockNeteaseMusic/Makefile +++ b/openwrt-packages/UnblockNeteaseMusic/Makefile @@ -1,12 +1,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=UnblockNeteaseMusic -PKG_VERSION:=0.27.8 +PKG_VERSION:=0.27.8-patch.1 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/UnblockNeteaseMusic/server/tar.gz/v${PKG_VERSION}? -PKG_HASH:=eae9bf5ad40e4d0fee9a5c9db6519e061ad13e0803d72dae4f08518f13a1e6e0 +PKG_HASH:=96b36e094614abaede3651286c26f5ca4aef1da684e1936f5678f527231906ef PKG_SOURCE_SUBDIR:=$(PKG_NAME) PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_SOURCE_SUBDIR) diff --git a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua index 6df0021535..806095faec 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua @@ -82,66 +82,34 @@ local doh_validate = function(self, value, t) return value end end - return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP" + return nil, translatef("%s request address","DoH") .. " " .. translate("Format must be:") .. " URL,IP" end local chinadns_dot_validate = function(self, value, t) local function isValidDoTString(s) - local prefix = "tls://" - if s:sub(1, #prefix) ~= prefix then - return false - end - local address = s:sub(#prefix + 1) + if s:sub(1, 6) ~= "tls://" then return false end + local address = s:sub(7) local at_index = address:find("@") local hash_index = address:find("#") - local domain, ip, port - if at_index then - if hash_index then - domain = address:sub(1, at_index - 1) - ip = address:sub(at_index + 1, hash_index - 1) - port = address:sub(hash_index + 1) - else - domain = address:sub(1, at_index - 1) - ip = address:sub(at_index + 1) - port = nil - end - else - if hash_index then - ip = address:sub(1, hash_index - 1) - port = address:sub(hash_index + 1) - else - ip = address - port = nil - end - end - local function isValidPort(port) - if not port then return true end - local num = tonumber(port) - return num and num > 0 and num < 65536 - end - local function isValidDomain(domain) - if not domain then return true end - return #domain > 0 - end - local function isValidIP(ip) - return datatypes.ipaddr(ip) or datatypes.ip6addr(ip) - end - if not isValidIP(ip) or not isValidPort(port) then - return false - end - if not isValidDomain(domain) then + local ip, port + local domain = at_index and address:sub(1, at_index - 1) or nil + ip = at_index and address:sub(at_index + 1, (hash_index or 0) - 1) or address:sub(1, (hash_index or 0) - 1) + port = hash_index and address:sub(hash_index + 1) or nil + local num_port = tonumber(port) + if (port and (not num_port or num_port <= 0 or num_port >= 65536)) or + (domain and domain == "") or + (not datatypes.ipaddr(ip) and not datatypes.ip6addr(ip)) then return false end return true end - if value ~= "" then value = api.trim(value) if isValidDoTString(value) then return value end end - return nil, translate("Direct DNS") .. " DoT " .. translate("Format must be:") .. " tls://Domain@IP(#Port) or tls://IP(#Port)" + return nil, translatef("%s request address","DoT") .. " " .. translate("Format must be:") .. " tls://" .. translate("Domain") .. "@IP[#Port] | tls://IP[#Port]" end m:append(Template(appname .. "/global/status")) diff --git a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua index dcb6ced4f4..fbd858425f 100644 --- a/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/openwrt-passwall/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -1003,6 +1003,7 @@ function gen_config(var) end end) + --[[ if default_outbound_tag or default_balancer_tag then table.insert(rules, { type = "field", @@ -1011,6 +1012,7 @@ function gen_config(var) network = "tcp,udp" }) end + ]]-- routing = { domainStrategy = node.domainStrategy or "AsIs", diff --git a/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po b/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po index 723d13c74e..962ad13b6f 100644 --- a/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po +++ b/openwrt-passwall/luci-app-passwall/po/zh-cn/passwall.po @@ -142,6 +142,9 @@ msgstr "配置不当" msgid "Make sure socks service is available on this address." msgstr "请确保此 Socks 服务可用。" +msgid "%s request address" +msgstr "%s 请求地址" + msgid "Format must be:" msgstr "格式必须为:" diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh index 43199a278a..ba0bdadc85 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/app.sh @@ -1434,6 +1434,7 @@ start_dns() { doh) remote_dns_doh=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query") _args="${_args} remote_dns_doh=${remote_dns_doh}" + echolog " - Sing-Box DNS(${TUN_DNS}) -> ${remote_dns_doh}" local _doh_url=$(echo $remote_dns_doh | awk -F ',' '{print $1}') local _doh_host_port=$(lua_api "get_domain_from_url(\"${_doh_url}\")") @@ -1445,7 +1446,6 @@ start_dns() { [ "${_is_ip}" = "true" ] && _doh_bootstrap=${_doh_host} [ -n "${_doh_bootstrap}" ] && REMOTE_DNS=${_doh_bootstrap}:${_doh_port} unset _doh_url _doh_host_port _doh_host _is_ip _doh_port _doh_bootstrap - echolog " - Sing-Box DNS(${TUN_DNS}) -> ${remote_dns_doh}" ;; esac _args="${_args} dns_socks_address=127.0.0.1 dns_socks_port=${tcp_node_socks_port}" @@ -1472,6 +1472,17 @@ start_dns() { remote_dns_doh=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query") _args="${_args} remote_dns_doh=${remote_dns_doh}" echolog " - Xray DNS(${TUN_DNS}) -> (${remote_dns_doh})(A/AAAA) + tcp://${REMOTE_DNS}" + + local _doh_url=$(echo $remote_dns_doh | awk -F ',' '{print $1}') + local _doh_host_port=$(lua_api "get_domain_from_url(\"${_doh_url}\")") + local _doh_host=$(echo $_doh_host_port | awk -F ':' '{print $1}') + local _is_ip=$(lua_api "is_ip(\"${_doh_host}\")") + local _doh_port=$(echo $_doh_host_port | awk -F ':' '{print $2}') + [ -z "${_doh_port}" ] && _doh_port=443 + local _doh_bootstrap=$(echo $remote_dns_doh | cut -d ',' -sf 2-) + [ "${_is_ip}" = "true" ] && _doh_bootstrap=${_doh_host} + [ -n "${_doh_bootstrap}" ] && REMOTE_DNS=${REMOTE_DNS},${_doh_bootstrap}:${_doh_port} + unset _doh_url _doh_host_port _doh_host _is_ip _doh_port _doh_bootstrap else echolog " - Xray DNS(${TUN_DNS}) -> tcp://${REMOTE_DNS}" fi diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/rule_update.lua b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/rule_update.lua index b1e4da099a..d7b5a9100f 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/rule_update.lua +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/rule_update.lua @@ -333,14 +333,14 @@ local function fetch_geosite() local json = jsonc.parse(content) if json.tag_name and json.assets then for _, v in ipairs(json.assets) do - if v.name and v.name == "geosite.dat.sha256sum" then + if v.name and (v.name == "geosite.dat.sha256sum" or v.name == "dlc.dat.sha256sum") then local sret = curl(v.browser_download_url, "/tmp/geosite.dat.sha256sum") if sret == 200 then local f = io.open("/tmp/geosite.dat.sha256sum", "r") local content = f:read() f:close() f = io.open("/tmp/geosite.dat.sha256sum", "w") - f:write(content:gsub("geosite.dat", "/tmp/geosite.dat"), "") + f:write(content:gsub("[^%s]+.dat", "/tmp/geosite.dat"), "") f:close() if nixio.fs.access(asset_location .. "geosite.dat") then @@ -351,7 +351,7 @@ local function fetch_geosite() end end for _2, v2 in ipairs(json.assets) do - if v2.name and v2.name == "geosite.dat" then + if v2.name and (v2.name == "geosite.dat" or v2.name == "dlc.dat") then sret = curl(v2.browser_download_url, "/tmp/geosite.dat") if luci.sys.call('sha256sum -c /tmp/geosite.dat.sha256sum > /dev/null 2>&1') == 0 then luci.sys.call(string.format("mkdir -p %s && cp -f %s %s", asset_location, "/tmp/geosite.dat", asset_location .. "geosite.dat")) diff --git a/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_xray.lua index 20349b44dc..8cb2989b9d 100644 --- a/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/openwrt-passwall2/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -1010,7 +1010,7 @@ function gen_config(var) end end end) - +--[[ if default_outboundTag or default_balancerTag then table.insert(rules, { _flag = "default", @@ -1020,7 +1020,7 @@ function gen_config(var) network = "tcp,udp" }) end - +]] routing = { domainStrategy = node.domainStrategy or "AsIs", domainMatcher = node.domainMatcher or "hybrid", diff --git a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua index 6df0021535..806095faec 100644 --- a/small/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua +++ b/small/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua @@ -82,66 +82,34 @@ local doh_validate = function(self, value, t) return value end end - return nil, translate("DoH request address") .. " " .. translate("Format must be:") .. " URL,IP" + return nil, translatef("%s request address","DoH") .. " " .. translate("Format must be:") .. " URL,IP" end local chinadns_dot_validate = function(self, value, t) local function isValidDoTString(s) - local prefix = "tls://" - if s:sub(1, #prefix) ~= prefix then - return false - end - local address = s:sub(#prefix + 1) + if s:sub(1, 6) ~= "tls://" then return false end + local address = s:sub(7) local at_index = address:find("@") local hash_index = address:find("#") - local domain, ip, port - if at_index then - if hash_index then - domain = address:sub(1, at_index - 1) - ip = address:sub(at_index + 1, hash_index - 1) - port = address:sub(hash_index + 1) - else - domain = address:sub(1, at_index - 1) - ip = address:sub(at_index + 1) - port = nil - end - else - if hash_index then - ip = address:sub(1, hash_index - 1) - port = address:sub(hash_index + 1) - else - ip = address - port = nil - end - end - local function isValidPort(port) - if not port then return true end - local num = tonumber(port) - return num and num > 0 and num < 65536 - end - local function isValidDomain(domain) - if not domain then return true end - return #domain > 0 - end - local function isValidIP(ip) - return datatypes.ipaddr(ip) or datatypes.ip6addr(ip) - end - if not isValidIP(ip) or not isValidPort(port) then - return false - end - if not isValidDomain(domain) then + local ip, port + local domain = at_index and address:sub(1, at_index - 1) or nil + ip = at_index and address:sub(at_index + 1, (hash_index or 0) - 1) or address:sub(1, (hash_index or 0) - 1) + port = hash_index and address:sub(hash_index + 1) or nil + local num_port = tonumber(port) + if (port and (not num_port or num_port <= 0 or num_port >= 65536)) or + (domain and domain == "") or + (not datatypes.ipaddr(ip) and not datatypes.ip6addr(ip)) then return false end return true end - if value ~= "" then value = api.trim(value) if isValidDoTString(value) then return value end end - return nil, translate("Direct DNS") .. " DoT " .. translate("Format must be:") .. " tls://Domain@IP(#Port) or tls://IP(#Port)" + return nil, translatef("%s request address","DoT") .. " " .. translate("Format must be:") .. " tls://" .. translate("Domain") .. "@IP[#Port] | tls://IP[#Port]" end m:append(Template(appname .. "/global/status")) diff --git a/small/luci-app-passwall/luasrc/passwall/util_xray.lua b/small/luci-app-passwall/luasrc/passwall/util_xray.lua index dcb6ced4f4..fbd858425f 100644 --- a/small/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/small/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -1003,6 +1003,7 @@ function gen_config(var) end end) + --[[ if default_outbound_tag or default_balancer_tag then table.insert(rules, { type = "field", @@ -1011,6 +1012,7 @@ function gen_config(var) network = "tcp,udp" }) end + ]]-- routing = { domainStrategy = node.domainStrategy or "AsIs", diff --git a/small/luci-app-passwall/po/zh-cn/passwall.po b/small/luci-app-passwall/po/zh-cn/passwall.po index 723d13c74e..962ad13b6f 100644 --- a/small/luci-app-passwall/po/zh-cn/passwall.po +++ b/small/luci-app-passwall/po/zh-cn/passwall.po @@ -142,6 +142,9 @@ msgstr "配置不当" msgid "Make sure socks service is available on this address." msgstr "请确保此 Socks 服务可用。" +msgid "%s request address" +msgstr "%s 请求地址" + msgid "Format must be:" msgstr "格式必须为:" diff --git a/small/luci-app-passwall/root/usr/share/passwall/app.sh b/small/luci-app-passwall/root/usr/share/passwall/app.sh index 43199a278a..ba0bdadc85 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/small/luci-app-passwall/root/usr/share/passwall/app.sh @@ -1434,6 +1434,7 @@ start_dns() { doh) remote_dns_doh=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query") _args="${_args} remote_dns_doh=${remote_dns_doh}" + echolog " - Sing-Box DNS(${TUN_DNS}) -> ${remote_dns_doh}" local _doh_url=$(echo $remote_dns_doh | awk -F ',' '{print $1}') local _doh_host_port=$(lua_api "get_domain_from_url(\"${_doh_url}\")") @@ -1445,7 +1446,6 @@ start_dns() { [ "${_is_ip}" = "true" ] && _doh_bootstrap=${_doh_host} [ -n "${_doh_bootstrap}" ] && REMOTE_DNS=${_doh_bootstrap}:${_doh_port} unset _doh_url _doh_host_port _doh_host _is_ip _doh_port _doh_bootstrap - echolog " - Sing-Box DNS(${TUN_DNS}) -> ${remote_dns_doh}" ;; esac _args="${_args} dns_socks_address=127.0.0.1 dns_socks_port=${tcp_node_socks_port}" @@ -1472,6 +1472,17 @@ start_dns() { remote_dns_doh=$(config_t_get global remote_dns_doh "https://1.1.1.1/dns-query") _args="${_args} remote_dns_doh=${remote_dns_doh}" echolog " - Xray DNS(${TUN_DNS}) -> (${remote_dns_doh})(A/AAAA) + tcp://${REMOTE_DNS}" + + local _doh_url=$(echo $remote_dns_doh | awk -F ',' '{print $1}') + local _doh_host_port=$(lua_api "get_domain_from_url(\"${_doh_url}\")") + local _doh_host=$(echo $_doh_host_port | awk -F ':' '{print $1}') + local _is_ip=$(lua_api "is_ip(\"${_doh_host}\")") + local _doh_port=$(echo $_doh_host_port | awk -F ':' '{print $2}') + [ -z "${_doh_port}" ] && _doh_port=443 + local _doh_bootstrap=$(echo $remote_dns_doh | cut -d ',' -sf 2-) + [ "${_is_ip}" = "true" ] && _doh_bootstrap=${_doh_host} + [ -n "${_doh_bootstrap}" ] && REMOTE_DNS=${REMOTE_DNS},${_doh_bootstrap}:${_doh_port} + unset _doh_url _doh_host_port _doh_host _is_ip _doh_port _doh_bootstrap else echolog " - Xray DNS(${TUN_DNS}) -> tcp://${REMOTE_DNS}" fi diff --git a/small/luci-app-passwall/root/usr/share/passwall/rule_update.lua b/small/luci-app-passwall/root/usr/share/passwall/rule_update.lua index b1e4da099a..d7b5a9100f 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/rule_update.lua +++ b/small/luci-app-passwall/root/usr/share/passwall/rule_update.lua @@ -333,14 +333,14 @@ local function fetch_geosite() local json = jsonc.parse(content) if json.tag_name and json.assets then for _, v in ipairs(json.assets) do - if v.name and v.name == "geosite.dat.sha256sum" then + if v.name and (v.name == "geosite.dat.sha256sum" or v.name == "dlc.dat.sha256sum") then local sret = curl(v.browser_download_url, "/tmp/geosite.dat.sha256sum") if sret == 200 then local f = io.open("/tmp/geosite.dat.sha256sum", "r") local content = f:read() f:close() f = io.open("/tmp/geosite.dat.sha256sum", "w") - f:write(content:gsub("geosite.dat", "/tmp/geosite.dat"), "") + f:write(content:gsub("[^%s]+.dat", "/tmp/geosite.dat"), "") f:close() if nixio.fs.access(asset_location .. "geosite.dat") then @@ -351,7 +351,7 @@ local function fetch_geosite() end end for _2, v2 in ipairs(json.assets) do - if v2.name and v2.name == "geosite.dat" then + if v2.name and (v2.name == "geosite.dat" or v2.name == "dlc.dat") then sret = curl(v2.browser_download_url, "/tmp/geosite.dat") if luci.sys.call('sha256sum -c /tmp/geosite.dat.sha256sum > /dev/null 2>&1') == 0 then luci.sys.call(string.format("mkdir -p %s && cp -f %s %s", asset_location, "/tmp/geosite.dat", asset_location .. "geosite.dat")) diff --git a/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua index 20349b44dc..8cb2989b9d 100644 --- a/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/small/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -1010,7 +1010,7 @@ function gen_config(var) end end end) - +--[[ if default_outboundTag or default_balancerTag then table.insert(rules, { _flag = "default", @@ -1020,7 +1020,7 @@ function gen_config(var) network = "tcp,udp" }) end - +]] routing = { domainStrategy = node.domainStrategy or "AsIs", domainMatcher = node.domainMatcher or "hybrid", diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index 97b94e6760..c5f0cc0de1 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -21,13 +21,13 @@ define Download/geoip HASH:=3b95b24108334c0a9f1f6480159437e7ce128bf45483469b534eea484ad7de8e endef -GEOSITE_VER:=20240829063032 +GEOSITE_VER:=20240831202649 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:=acabd214b0a05363f678baba64dfb745ffc551a9dea6d8c15abe0821a0cac5e9 + HASH:=8fba86084a952fd635f5a4728c14f7e5eafd225132013163072272859dbbd8cb endef GEOSITE_IRAN_VER:=202408260030 diff --git a/v2rayn/v2rayN/ProtosLib/ProtosLib.csproj b/v2rayn/v2rayN/ProtosLib/ProtosLib.csproj index 3af8c0dd6b..af2339ddfb 100644 --- a/v2rayn/v2rayN/ProtosLib/ProtosLib.csproj +++ b/v2rayn/v2rayN/ProtosLib/ProtosLib.csproj @@ -9,9 +9,9 @@ - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/v2rayn/v2rayN/ServiceLib/Common/DownloaderHelper.cs b/v2rayn/v2rayN/ServiceLib/Common/DownloaderHelper.cs index b41640392d..b08286e796 100644 --- a/v2rayn/v2rayN/ServiceLib/Common/DownloaderHelper.cs +++ b/v2rayn/v2rayN/ServiceLib/Common/DownloaderHelper.cs @@ -168,6 +168,10 @@ namespace ServiceLib.Common { progress.Report(101); } + else if (value.Error != null) + { + throw value.Error; + } } }; diff --git a/v2rayn/v2rayN/ServiceLib/Enums/EViewAction.cs b/v2rayn/v2rayN/ServiceLib/Enums/EViewAction.cs index 88954a78b7..9992daa306 100644 --- a/v2rayn/v2rayN/ServiceLib/Enums/EViewAction.cs +++ b/v2rayn/v2rayN/ServiceLib/Enums/EViewAction.cs @@ -38,5 +38,7 @@ DispatcherReload, DispatcherRefreshServersBiz, DispatcherRefreshIcon, + DispatcherCheckUpdate, + DispatcherCheckUpdateFinished, } } \ No newline at end of file diff --git a/v2rayn/v2rayN/ServiceLib/Handler/UpdateHandler.cs b/v2rayn/v2rayN/ServiceLib/Handler/UpdateHandler.cs index 96b35ac601..15c49e9e6c 100644 --- a/v2rayn/v2rayN/ServiceLib/Handler/UpdateHandler.cs +++ b/v2rayn/v2rayN/ServiceLib/Handler/UpdateHandler.cs @@ -50,6 +50,7 @@ namespace ServiceLib.Handler downloadHandle.Error += (sender2, args) => { _updateFunc(false, args.GetException().Message); + _updateFunc(false, ""); }; AbsoluteCompleted += (sender2, args) => { @@ -61,19 +62,20 @@ namespace ServiceLib.Handler url = args.Url; AskToDownload(downloadHandle, url, true).ContinueWith(task => { - _updateFunc(false, url); + _updateFunc(false, ""); }); } else { _updateFunc(false, args.Msg); + _updateFunc(false, ""); } }; _updateFunc(false, string.Format(ResUI.MsgStartUpdating, ECoreType.v2rayN)); - CheckUpdateAsync(ECoreType.v2rayN, preRelease); + CheckUpdateAsync(downloadHandle, ECoreType.v2rayN, preRelease); } - public void CheckUpdateCore(ECoreType type, Config config, Action update, bool preRelease) + public async void CheckUpdateCore(ECoreType type, Config config, Action update, bool preRelease) { _config = config; _updateFunc = update; @@ -103,7 +105,8 @@ namespace ServiceLib.Handler }; downloadHandle.Error += (sender2, args) => { - _updateFunc(true, args.GetException().Message); + _updateFunc(false, args.GetException().Message); + _updateFunc(false, ""); }; AbsoluteCompleted += (sender2, args) => @@ -116,16 +119,17 @@ namespace ServiceLib.Handler url = args.Url; AskToDownload(downloadHandle, url, true).ContinueWith(task => { - _updateFunc(false, url); + _updateFunc(false, ""); }); } else { _updateFunc(false, args.Msg); + _updateFunc(false, ""); } }; _updateFunc(false, string.Format(ResUI.MsgStartUpdating, type)); - CheckUpdateAsync(type, preRelease); + CheckUpdateAsync(downloadHandle, type, preRelease); } public void UpdateSubscriptionProcess(Config config, string subId, bool blProxy, Action update) @@ -267,6 +271,7 @@ namespace ServiceLib.Handler { await UpdateGeoFile("geosite", _config, update); await UpdateGeoFile("geoip", _config, update); + _updateFunc(true, string.Format(ResUI.MsgDownloadGeoFileSuccessfully, "geo")); }); } @@ -282,14 +287,14 @@ namespace ServiceLib.Handler #region private - private async void CheckUpdateAsync(ECoreType type, bool preRelease) + private async void CheckUpdateAsync(DownloadHandler downloadHandle, ECoreType type, bool preRelease) { try { var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(type); string url = coreInfo.coreReleaseApiUrl; - var result = await (new DownloadHandler()).DownloadStringAsync(url, true, Global.AppName); + var result = await downloadHandle.DownloadStringAsync(url, true, Global.AppName); if (!Utils.IsNullOrEmpty(result)) { ResponseHandler(type, result, preRelease); @@ -483,7 +488,7 @@ namespace ServiceLib.Handler //} //if (blDownload) //{ - await downloadHandle.DownloadFileAsync(url, true, 600); + await downloadHandle.DownloadFileAsync(url, true, 60); //} } diff --git a/v2rayn/v2rayN/ServiceLib/Models/CheckUpdateItem.cs b/v2rayn/v2rayN/ServiceLib/Models/CheckUpdateItem.cs new file mode 100644 index 0000000000..d3886d41bc --- /dev/null +++ b/v2rayn/v2rayN/ServiceLib/Models/CheckUpdateItem.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ServiceLib.Models +{ + public class CheckUpdateItem + { + public bool? isSelected { get; set; } + public string coreType { get; set; } + public string? remarks { get; set; } + public string? fileName { get; set; } + public bool? isFinished { get; set; } + } +} diff --git a/v2rayn/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs b/v2rayn/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs new file mode 100644 index 0000000000..882b66844e --- /dev/null +++ b/v2rayn/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs @@ -0,0 +1,323 @@ +using DynamicData; +using DynamicData.Binding; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; +using Splat; +using System.Diagnostics; +using System.Reactive; + +namespace ServiceLib.ViewModels +{ + public class CheckUpdateViewModel : MyReactiveObject + { + private const string _geo = "GeoFiles"; + private List _lstUpdated = []; + + private IObservableCollection _checkUpdateItem = new ObservableCollectionExtended(); + public IObservableCollection CheckUpdateItems => _checkUpdateItem; + public ReactiveCommand CheckUpdateCmd { get; } + [Reactive] public bool EnableCheckPreReleaseUpdate { get; set; } + [Reactive] public bool IsCheckUpdate { get; set; } + [Reactive] public bool AutoRun { get; set; } + + public CheckUpdateViewModel(Func>? updateView) + { + _config = LazyConfig.Instance.Config; + _updateView = updateView; + _noticeHandler = Locator.Current.GetService(); + + RefreshSubItems(); + + CheckUpdateCmd = ReactiveCommand.Create(() => + { + CheckUpdate(); + }); + EnableCheckPreReleaseUpdate = _config.guiItem.checkPreReleaseUpdate; + IsCheckUpdate = true; + + this.WhenAnyValue( + x => x.EnableCheckPreReleaseUpdate, + y => y == true) + .Subscribe(c => { _config.guiItem.checkPreReleaseUpdate = EnableCheckPreReleaseUpdate; }); + } + + private void RefreshSubItems() + { + _checkUpdateItem.Clear(); + + _checkUpdateItem.Add(new CheckUpdateItem() + { + isSelected = false, + coreType = ECoreType.v2rayN.ToString(), + remarks = ResUI.menuCheckUpdate, + }); + _checkUpdateItem.Add(new CheckUpdateItem() + { + isSelected = true, + coreType = ECoreType.Xray.ToString(), + remarks = ResUI.menuCheckUpdate, + }); + _checkUpdateItem.Add(new CheckUpdateItem() + { + isSelected = true, + coreType = ECoreType.mihomo.ToString(), + remarks = ResUI.menuCheckUpdate, + }); + _checkUpdateItem.Add(new CheckUpdateItem() + { + isSelected = true, + coreType = ECoreType.sing_box.ToString(), + remarks = ResUI.menuCheckUpdate, + }); + _checkUpdateItem.Add(new CheckUpdateItem() + { + isSelected = true, + coreType = _geo, + remarks = ResUI.menuCheckUpdate, + }); + } + + private void CheckUpdate() + { + _lstUpdated.Clear(); + + for (int k = _checkUpdateItem.Count - 1; k >= 0; k--) + { + var item = _checkUpdateItem[k]; + if (item.isSelected == true) + { + IsCheckUpdate = false; + _lstUpdated.Add(new CheckUpdateItem() { coreType = item.coreType }); + UpdateView(item.coreType, "..."); + if (item.coreType == _geo) + { + CheckUpdateGeo(); + } + else if (item.coreType == ECoreType.v2rayN.ToString()) + { + CheckUpdateN(EnableCheckPreReleaseUpdate); + } + else if (item.coreType == ECoreType.mihomo.ToString()) + { + CheckUpdateCore(item, false); + } + else + { + CheckUpdateCore(item, EnableCheckPreReleaseUpdate); + } + } + } + } + + private void UpdatedPlusPlus(string coreType, string fileName) + { + var item = _lstUpdated.FirstOrDefault(x => x.coreType == coreType); + if (item == null) + { + return; + } + item.isFinished = true; + if (!fileName.IsNullOrEmpty()) + { + item.fileName = fileName; + } + } + + private void CheckUpdateGeo() + { + void _updateUI(bool success, string msg) + { + UpdateView(_geo, msg); + if (success) + { + UpdatedPlusPlus(_geo, ""); + UpdateFinished(); + } + } + (new UpdateHandler()).UpdateGeoFileAll(_config, _updateUI); + } + + private void CheckUpdateN(bool preRelease) + { + //Check for standalone windows .Net version + if (Utils.IsWindows() + && File.Exists(Path.Combine(Utils.StartupPath(), "wpfgfx_cor3.dll")) + && File.Exists(Path.Combine(Utils.StartupPath(), "D3DCompiler_47_cor3.dll")) + ) + { + UpdateView(ResUI.UpdateStandalonePackageTip, ResUI.UpdateStandalonePackageTip); + return; + } + + void _updateUI(bool success, string msg) + { + if (success) + { + UpdateView(ECoreType.v2rayN.ToString(), ResUI.OperationSuccess); + UpdatedPlusPlus(ECoreType.v2rayN.ToString(), msg); + UpdateFinished(); + } + else + { + if (msg.IsNullOrEmpty()) + { + UpdatedPlusPlus(ECoreType.v2rayN.ToString(), ""); + UpdateFinished(); + } + else + { + UpdateView(ECoreType.v2rayN.ToString(), msg); + } + } + } + (new UpdateHandler()).CheckUpdateGuiN(_config, _updateUI, preRelease); + } + + private void CheckUpdateCore(CheckUpdateItem item, bool preRelease) + { + void _updateUI(bool success, string msg) + { + if (success) + { + UpdateView(item.coreType, ResUI.MsgUpdateV2rayCoreSuccessfullyMore); + + UpdatedPlusPlus(item.coreType, msg); + UpdateFinished(); + } + else + { + if (msg.IsNullOrEmpty()) + { + UpdatedPlusPlus(item.coreType, ""); + UpdateFinished(); + } + else + { + UpdateView(item.coreType, msg); + } + } + } + var type = (ECoreType)Enum.Parse(typeof(ECoreType), item.coreType); + (new UpdateHandler()).CheckUpdateCore(type, _config, _updateUI, preRelease); + } + + private void UpdateFinished() + { + if (_lstUpdated.Count > 0 && _lstUpdated.Count(x => x.isFinished == true) == _lstUpdated.Count) + { + _updateView?.Invoke(EViewAction.DispatcherCheckUpdateFinished, false); + + UpgradeCore(); + + if (_lstUpdated.Any(x => x.coreType == ECoreType.v2rayN.ToString() && x.isFinished == true)) + { + UpgradeN(); + } + _updateView?.Invoke(EViewAction.DispatcherCheckUpdateFinished, true); + } + } + + public void UpdateFinishedResult(bool blReload) + { + if (blReload) + { + IsCheckUpdate = true; + Locator.Current.GetService()?.Reload(); + } + else + { + Locator.Current.GetService()?.CloseCore(); + } + } + + private void UpgradeN() + { + try + { + var fileName = _lstUpdated.FirstOrDefault(x => x.coreType == ECoreType.v2rayN.ToString())?.fileName; + if (fileName.IsNullOrEmpty()) + { + return; + } + + Process process = new() + { + StartInfo = new ProcessStartInfo + { + FileName = "v2rayUpgrade", + Arguments = fileName.AppendQuotes(), + WorkingDirectory = Utils.StartupPath() + } + }; + process.Start(); + if (process.Id > 0) + { + Locator.Current.GetService()?.MyAppExitAsync(false); + } + } + catch (Exception ex) + { + UpdateView(ECoreType.v2rayN.ToString(), ex.Message); + } + } + + private void UpgradeCore() + { + foreach (var item in _lstUpdated) + { + if (item.fileName.IsNullOrEmpty()) + { + continue; + } + + var fileName = Utils.GetTempPath(Utils.GetDownloadFileName(item.fileName)); + if (!File.Exists(fileName)) + { + continue; + } + string toPath = Utils.GetBinPath("", item.coreType); + + if (fileName.Contains(".tar.gz")) + { + //It's too complicated to unzip. TODO + } + else if (fileName.Contains(".gz")) + { + FileManager.UncompressedFile(fileName, toPath, item.coreType); + } + else + { + FileManager.ZipExtractToFile(fileName, toPath, _config.guiItem.ignoreGeoUpdateCore ? "geo" : ""); + } + + UpdateView(item.coreType, ResUI.MsgUpdateV2rayCoreSuccessfully); + + if (File.Exists(fileName)) + { + File.Delete(fileName); + } + } + } + + private void UpdateView(string coreType, string msg) + { + var item = new CheckUpdateItem() + { + coreType = coreType, + remarks = msg, + }; + _updateView?.Invoke(EViewAction.DispatcherCheckUpdate, item); + } + + public void UpdateViewResult(CheckUpdateItem item) + { + var found = _checkUpdateItem.FirstOrDefault(t => t.coreType == item.coreType); + if (found != null) + { + var itemCopy = JsonUtils.DeepCopy(found); + itemCopy.remarks = item.remarks; + _checkUpdateItem.Replace(found, itemCopy); + } + } + } +} \ No newline at end of file diff --git a/v2rayn/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs b/v2rayn/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs index bff2d462ff..7651f25c08 100644 --- a/v2rayn/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs +++ b/v2rayn/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs @@ -852,7 +852,7 @@ namespace ServiceLib.ViewModels }); } - private void CloseCore() + public void CloseCore() { ConfigHandler.SaveConfig(_config, false); diff --git a/v2rayn/v2rayN/v2rayN/Views/CheckUpdateView.xaml b/v2rayn/v2rayN/v2rayN/Views/CheckUpdateView.xaml new file mode 100644 index 0000000000..e20138a3a5 --- /dev/null +++ b/v2rayn/v2rayN/v2rayN/Views/CheckUpdateView.xaml @@ -0,0 +1,112 @@ + + + + + + + + +