Repository navigation
Releases: having5548/dsh-downloader
Release list
v0.6.0 — harnessProxy:让 harness 自身出网也走内核
dsh-downloader v0.6.0 — harnessProxy:让 harness 自身出网也走内核
原先只有 dsh_download 与 dsh_run_proxied 走代理。这一版把内核开放给 harness 自身。
用法(三步)
- 设置 → 下载代理 → 打开 「开放给 harness」(
harnessProxy),端口默认17890 - 调
dsh_harness_proxy({ action: "apply" })—— 写入$DSH_HOME/.env(写前备份) - 重启 DSH
覆盖 / 不覆盖
| 会跟着走 | 不会跟着走 |
|---|---|
web_fetch |
Electron 渲染进程与内嵌 webview |
shell 子进程里的 curl / git / npm |
系统里其它程序(浏览器、别的 App) |
| MCP 的 HTTP 传输 | |
| jobs / workflow / subagent 派生的进程 |
为什么 webview 不行:Chromium 读的是系统代理,不读环境变量。插件不会去改系统代理(那会波及全机,且与「只服务 DSH」的边界冲突)。想覆盖真浏览器只能设系统代理,而且需要一个真的 HTTP/SOCKS 代理。
设计要点
- 令牌必须持久化:
.env里要写死它,随机令牌每次重启都会407。存在<数据目录>/harness-token.txt(mode 0600)。 - 端口必须固定:
.env指不到随机端口。被占用时自动退回随机端口并 warn —— 此时开放实际不生效,status会报「与配置不一致」。 NO_PROXY自动补上回环 + 国内 AI 平台域名:前者避免「代理指向自己」的循环,后者保证代理抖动时不打断模型长连接。- 不会有自指环:内核与订阅自己拉的流量走
httpFlow(Nodehttp/https模块),不受全局 undici dispatcher 影响 —— 插件里没有用fetch()的核心代码,这一点是刻意确认过的。 - 内核从「单令牌」改为令牌集合(本进程令牌 + 持久化令牌),未知令牌照旧
407;SOCKS5 在门禁开启时照旧直接拒绝。
兼容
harnessProxy 默认关闭。不开时内核仍是随机端口 + 随机令牌,只服务本插件自己的下载,行为与 0.5.3 完全一致。
质量
node test/smoke.mjs → 406 passed, 0 failed(上一版 368)。新增:令牌持久化与只读模式、URL 入参校验、6 个 *_PROXY 键增删的幂等性、备份与还原、NO_PROXY 合并、不一致检测,以及内核同时接受两个令牌 / 未知令牌仍被拒的运行时断言。
安装
dsh plugin --profile desktop add @having5548/dsh-downloader装完重启 DSH。
MIT。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。
v0.5.3 — 修一个会把 DSH 宿主崩掉的严重问题
dsh-downloader v0.5.3 — 修一个会把 DSH 宿主崩掉的严重问题
现象
宿主在 2026-10-11 连续两次异常退出(crash-2026-10-11T03-46-46 / 03-48-03),两份日志的栈指向同一处:
dsh: fatal uncaught exception: Error: write EPIPE
at Writable.write (node:internal/streams/writable:508:10)
at Object.write (.../@having5548/dsh-downloader/lib/core/transports.js:598:28)
at Socket.<anonymous> (.../@having5548/dsh-downloader/lib/core/proxy-server.js:154:9)
根因
nativeConnect() 用 stdio: ["pipe","pipe","pipe"] 起 Go 连接器,但三根管道一个 error 监听都没挂。
连接器进程一死(连接失败 / 超时 / 被 kill),管道随即断裂,之后任何一次写入都会让 child.stdin 抛出 EPIPE —— 而在 Node 里没有监听者的 error 事件就是未捕获异常,直接把宿主带走。
原有的 ended 标志挡不住这个竞态:写入可能排在一个已经断掉的管道上,而 exit 事件还没派发。
修法(三层)
- 新增
stdioFace(child):给stdin/stdout/stderr与子进程本身都挂error监听,写入再包一层 try/catch(防同步抛出),并保留连接器最后的 stderr 供排查; ProxyServer.#relay()里的face.write(chunk)包 try/catch,失败即关闭上游并销毁客户端连接;- 新增独立子进程回归测试:让子进程关掉 stdin 但继续活着(于是
ended不会置位、管道却已断),再灌 1.25 MB 数据。
这条测试是有牙齿的 —— 用修复前的写法跑同一个探针必定崩溃(实测 exit=1、code: 'EOF'),修复后存活。
质量
node test/smoke.mjs → 368 passed, 0 failed(上一版 366)。
安装
dsh plugin --profile desktop add @having5548/dsh-downloader或从 Release 装。装完重启 DSH(这个修复必须重启才生效 —— 崩溃路径在已加载的旧模块里)。
MIT。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。
v0.5.2 — 让 dsh_run_proxied 对 git 真正可用
dsh-downloader v0.5.2 — 让 dsh_run_proxied 对 git 真正可用
两处都是把 dsh_run_proxied 真正用起来时才暴露的:git push 打插件内核必定失败。
修复
① 内核的 407 挑战写成了 Bearer,客户端无法应答
- 现象:
git push报CONNECT tunnel failed, response 407;GIT_CURL_VERBOSE=1显示 git 发的 CONNECT 里根本没有Proxy-Authorization,而应答是Proxy-Authenticate: Bearer realm="dsh-downloader" - 根因:内核两种凭据都接受(
Bearer <令牌>与Basic dsh:<令牌>),但挑战只宣告了Bearer—— curl 拿到自己满足不了的方案会直接放弃重试;而 git 连预发Proxy-Authorization都不做(只有 curl 会预发),于是必然吃 407 - 修法:挑战改成
Proxy-Authenticate: Basic realm="dsh-downloader"。两种凭据照旧都接受,只是宣告了客户端普遍能应答的那一种
② dsh_run_proxied 没有为 git 单独配好代理
- 现象:407 解决后,仍要手写
git -c http.proxy=… -c http.proxyAuthMethod=basic才通 - 根因:git 不吃「URL 里带凭据的环境变量」这一套,不会把凭据预发给 libcurl
- 修法:
buildShellPrefix()额外通过GIT_CONFIG_COUNT/GIT_CONFIG_KEY_n/GIT_CONFIG_VALUE_n注入http.proxy(带凭据的同一个 URL)与http.proxyAuthMethod=basic。对非 git 命令完全无副作用,所以不做命令嗅探;bash与pwsh两种前缀都注入
⚠️ 顺带说明两件事
- 这两条修好后「走代理」这条路才是通的,但节点本身会整段时间性失效(实测连
upload.wikimedia.org都连不上)。那种情况下改用直连,或者换个订阅。 - 本机
github.com的解析里混过污染 IP(次级 DNS8.8.8.8的应答里带205.251.x/198.51.44.8/127.0.0.1)。直连可用时不要绕代理 —— 先比 DNS、再试直连,最后才上代理。
质量
node test/smoke.mjs → 366 passed, 0 failed(上一版 360)。新增「未带凭据的 CONNECT 收 407」「407 挑战宣告的是 Basic 而非 Bearer」以及 pwsh / bash 两种前缀里的 http.proxy、http.proxyAuthMethod、GIT_CONFIG_COUNT 断言。
安装
dsh plugin --profile desktop add https://github.com/having5548/dsh-downloader/releases/latest/download/having5548-dsh-downloader-0.5.2.tgz装完重启 DSH。
MIT。内核部分派生自 dsh-clash-proxy 0.2.0(MIT),连接器源码在 native/。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。
v0.5.1 — dsh_download 支持带鉴权的下载
dsh-downloader v0.5.1 — dsh_download 支持带鉴权的下载
新增
auth 参数(推荐) —— 只接受引用,token 由插件自己去取,不进会话记录:
| 取值 | 含义 |
|---|---|
gh |
插件跑 gh auth token --hostname github.com,从 GitHub CLI 凭据库读 |
env:变量名 |
读环境变量,如 auth: "env:GH_TOKEN" |
bearer:token |
字面量(会进会话记录,返回值里带提醒) |
headers 参数 —— 附加任意请求头。Host / Content-Length / Connection / Transfer-Encoding / Proxy-Authorization / Proxy-Connection / Upgrade 会被静默忽略,避免调用方把请求弄坏。
用法:
dsh_download({ url: "<archive_download_url>", save_path: "...", auth: "gh" })
这样 GitHub Actions 产物也能拿到 dsh_download 的全套能力:sha256、大小上限、多线程分片、停滞检测、失败回退。
变更
- 跨主机重定向会剥掉
Authorization/Cookie。GitHub 的archive_download_url会 302 到 blob 域,把凭据带过去既没用、又等于把 token 交给第三方主机,某些情况下还会被对端 400 拒绝。同主机跳转保持原样。 - 凭据贯穿每一条请求:初次探测、
downloadSegmented的每个 Range 分片、以及回退后的attemptSingleStream重试。
修复
- 分片请求漏传
headers(写这一版时自己踩的):trySegmented()组装downloadSegmented()参数时没带headers,于是带鉴权的分片下载每一条 Range 都被服务端回 401 → 触发回退单连接(结果正确,但白白退化成单线程)。已补上,并加断言钉死。
质量
node test/smoke.mjs → 360 passed, 0 failed(上一版 338)。新增:sanitizeHeaders 取舍、敏感头识别与剥离、resolveAuth 四条成功路径与四条失败路径、端到端鉴权下载(带头 200 / 不带头 401)、鉴权 + 分片、以及同域保留 / 跨域剥离凭据的重定向断言。
安装
dsh plugin --profile desktop add https://github.com/having5548/dsh-downloader/releases/latest/download/having5548-dsh-downloader-0.5.1.tgz装完重启 DSH。
MIT。内核部分派生自 dsh-clash-proxy 0.2.0(MIT),连接器源码在 native/。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。
v0.5.0 — 多线程下载 + 侧边栏实时流量
dsh-downloader v0.5.0 — 多线程下载 + 侧边栏实时流量
⚡ 多线程(分片)下载
服务端支持 Range 时,大文件自动分成 threads(默认 4)个连接并发下载。
关键不是"切成 N 份",而是怎么切。 固定等分只在各家网速相当时才快 —— 一条慢连接会把整体拖到「最慢分片 × 份数 ÷ 并发」。所以这里照搬 gopeed(internal/protocol/http/fetcher.go)的做法:
- 起始按
threads均分; - 谁先下完,谁就去偷「剩余字节最多的分片」的前半段(下限 512 KiB,太碎不值得单开请求);
- 慢分片被不断切走,快连接一直满载,直到全部抢完。
| 情况 | 行为 |
|---|---|
没有 accept-ranges: bytes |
单连接 |
| 文件 < 1 MiB | 单连接(协调开销大于收益) |
threads = 1 |
单连接 |
| 服务端嘴上支持 Range 却返回 200 | 检测到后回退单连接重下,绝不拼出坏文件 |
Content-Range 起点不符 / 合计字节数不符 |
同上 |
分片用定位写落进同一个文件的对应偏移,完成后按顺序流式算 sha256(分片乱序落盘,边下边算会算错)。返回值里的 via_threads / segments 说明实际走了哪条路。
📊 侧边栏实时流量
侧边栏页脚(设置图标旁)新增流量徽标:
↑ 1.2 MB/s 340 KB
↓ 3.4 MB/s 1.8 GB
- 只统计经过本插件内核的流量,不是全机网卡流量;
- 侧边栏收起成 56px 窄条时自动切极简排版,只显示下行速率;
- 后台标签页降到 5 秒一次;内核没跑时不占地方;
- 内核侧加了 1.2 秒采样缓存 —— 否则面板(5 秒)与徽标(1.5 秒)会互相偷走采样窗口,读数乱跳。
修复
fs.promises.FileHandle.write不接受回调。分片写入最初照fs.write的写法传了回调,该参数被静默忽略、Promise 永不 settle,整个下载挂死(实测:测试套件卡在分片那一步)。改为 await Promise 并校验bytesWritten。- 流量采样缓存(见上)。
质量
node test/smoke.mjs → 338 passed, 0 failed(上一版 305)。新增:supportsRanges / parseContentRange / planChunks / stealSlice 的边界,以及端到端分片下载(3 MiB、sha256 逐字节比对、4 与 8 分片、threads=1 走单连接、假 Range 服务器必须回退且结果仍正确、经插件规则内核的分片下载)。
安装
dsh plugin --profile desktop add https://github.com/having5548/dsh-downloader/releases/latest/download/having5548-dsh-downloader-0.5.0.tgz装完重启 DSH。
MIT。多线程设计参考 gopeed(GPL-3.0)的实现思路,代码为独立编写;内核部分派生自 dsh-clash-proxy 0.2.0(MIT)。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。
v0.4.0 — 订阅真正能用:三种格式 + hysteria2 混淆
dsh-downloader v0.4.0 — 订阅真正能用:三种格式 + hysteria2 混淆
你报的「proxyUrl 填了才有用、subscriptionUrl 填了没用而且不能选节点」,查出来是三件事叠在一起。你的订阅是 base64 分享链接列表,9 个节点全是 hysteria2 + salamander 混淆 —— 三个坑全踩上了。
① proxyUrl 会把订阅整个挤掉
- 现象:两者都填时状态显示
上游模式:explicit,节点列表只有一个configured-proxy,订阅从未被读取 - 根因:
#rebuild()的explicit分支先匹配并直接return,subscription分支根本走不到 - 修法:订阅优先 ——
订阅(节点配置 → subscriptionUrl)→ proxyUrl → 环境代理 → none。订阅给的是一份可选节点列表,proxyUrl只是一条固定上游;现在proxyUrl退居两用:抓订阅时当代理、订阅拿不到节点时兜底,并在原因里说明为何回退
② 订阅解析只认 YAML,不认分享链接列表
- 现象:解析你的订阅直接抛「订阅内容既不是 YAML,也不是 base64 包裹的 YAML」
- 根因:
parseSubscription()只试「原文 YAML」与「base64 → YAML」两条路 - 修法:新增
lib/core/share-links.js,支持hysteria2://(含 salamander 参数)、ss://(三种写法)、trojan://、vmess://、vless://(含 reality)、socks5://、http(s)://;明文与 base64 列表都能吃。认不出的行计数并报告,不再静默丢弃
③ 原生连接器没把混淆参数传下去
- 现象:接上连接器后 hysteria2 依然连不通(5 秒超时后关闭),且看不出原因
- 根因:
nativeConnect()漏传obfs/obfs-password;服务端拿不到混淆参数会直接丢掉我们的 QUIC 包,表现为"拨号超时"而不是认证失败 - 修法:补上字段;并给混淆包装补
SetReadBuffer/SetWriteBuffer消除 quic-go 警告(否则回退小缓冲区,掉吞吐)
新增:自带 Go 原生连接器
lib/native/connector.exe 现在随包发布(原先未打包,这两类节点被静默跳过)。源码一并放在 native/,可复现编译:
native/salamander.go(新增):线格式 =8 字节随机 salt ‖ (明文 ⊕ BLAKE2b-256(password‖salt) keystream),与 hysteria2 参考实现及sagernet/sing-quic/hysteria2一致native/hysteria2.go:改用quic.Transport{Conn: 包装后的 PacketConn}+Transport.Dial()——quic.DialAddr()会自建 socket,混淆没有插进去的位置
实测(你的真实订阅)
| 项目 | 结果 |
|---|---|
| 订阅抓取 | 200,2540 字节;subscription-userinfo 报告已用 ≈49.7 GB / 300 GB |
| 解析 | 9 个节点全部拿到,名字 / sni / obfs 齐全 |
| 连通性(经插件 transport) | 9 个里 8 个通(HTTP/1.1 204);唯一失败的「香港-移动网络专属」名字即说明限移动网络 |
| 对照:不带混淆 | dial failed: hysteria2 quic dial: timeout —— 证明混淆是必需的 |
| 端到端 · 国内 | 直连,102356 字节,sha256 与历史一致 |
| 端到端 · 境外 | route=proxy,经节点下载 registry.npmjs.org 成功 102356 字节 |
质量
node test/smoke.mjs → 305 passed, 0 failed(上一版 255)。
安装
dsh plugin --profile desktop add https://github.com/having5548/dsh-downloader/releases/latest/download/having5548-dsh-downloader-0.4.0.tgz装完重启 DSH。
MIT。内核部分派生自 dsh-clash-proxy 0.2.0(MIT),连接器源码在 native/ 并保留出处。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。
v0.3.1 — 实测发现的两处 bug
dsh-downloader v0.3.1 — 实测发现的两处 bug
两处都是装上真机实测才暴露的 —— 离线单测覆盖不到「与宿主其它工具/服务交互」的那一层。
修复
① dsh_run_proxied 委派给 shell 工具时漏传必填的 description
- 现象:
execute=true必然失败,报invalid arguments: missing required property "description" - 根因:
dsh-tool-pwsh/dsh-tool-bash的description是必填参数,而组装委派参数时只带了command - 修法:抽出纯函数
buildShellToolArguments(),总是带description(调用方优先,否则按命令自动生成);dsh_run_proxied也新增了可选的description参数
② 挂载 / 重启后第一次调 dsh_run_proxied 报「代理内核还没就绪」
- 现象:刚装完插件、或刚重启 DSH 时立刻调用必定失败;先跑一次
dsh_proxy_status再调就好了 - 根因:内核懒启动(第一次
resolve()才监听端口、生成令牌),而工具直接读shellProxyEnv() - 修法:工具先
await upstream.resolve();并在apply()末尾异步预热一次(不 await,慢订阅不拖挂载),让同步的工具守卫也能尽早生效
实测覆盖到的(都通过)
| 场景 | 结果 |
|---|---|
裸的境外 curl(无代理) |
被守卫拦下,提示改用 dsh_run_proxied |
裸的国内 curl(百度) |
放行,http=200 / 0.117s |
命令里已带 HTTP_PROXY |
放行(不误拦修正后的重试) |
dsh_run_proxied 的 execute=false |
正确拼出 8 个代理变量 + 40 个 AI 域名的 NO_PROXY |
| 国内目标经内核 | 规则引擎判定直连,http=200 / 0.106s |
| 境外目标经内核 | 令牌鉴权通过(否则会是 407)、判定走代理、上游失败回 502 |
dsh_download 国内 |
直连成功,sha256 与历史一致 |
dsh_download 境外 |
走代理,错误信息带上游模式与建议 |
质量
node test/smoke.mjs → 255 passed, 0 failed(上一版 250)。新增 5 条钉住 buildShellToolArguments()。
安装
dsh plugin --profile desktop add https://github.com/having5548/dsh-downloader/releases/latest/download/having5548-dsh-downloader-0.3.1.tgz装完重启 DSH —— 实测确认:remove + install 只更新磁盘,运行中的宿主仍执行已加载的旧模块。
MIT。内核部分派生自 dsh-clash-proxy 0.2.0(MIT),各文件头部保留出处。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。
v0.3.0 — git / curl 下载境外内容也走这个代理
dsh-downloader v0.3.0 — git / curl 下载境外内容也走这个代理
先说清楚技术事实
git / curl 跑在 shell 子进程里,工具型插件无法在进程外截获它们。所以这件事只能做成两条腿,缺一条都不成立。
① 给它一条带上代理的命令:dsh_run_proxied
dsh_run_proxied({ command: "git clone https://github.com/x/y.git" })
它为这一次 shell 调用注入代理环境(HTTP_PROXY / HTTPS_PROXY / ALL_PROXY 及小写形式,指向本插件内核),然后委派给真正的 shell 工具执行 —— 沙箱与权限预设照常生效,不是绕过策略的后门。
- 国内目标仍由内核判定直连;国内 AI 平台域名写进
NO_PROXY,连内核都不经过。 execute=false时只返回拼好的命令,自己用 pwsh 跑也行。
② 检测到就拦:guardShellDownloads(默认开)
当 shell 命令看起来要从境外下载、又没带代理时,命令会被拦下来并提示改用 dsh_run_proxied(下文件则用 dsh_download)。
不会误拦的情况:命令里已带代理(HTTP_PROXY / curl -x / --proxy / git -c http.proxy);目标是回环或内网;SSH 远端(git@github.com:… 不走 HTTP,代理环境变量对它无效);内核没有可用出口(拦下来却没有替代方案比不拦更糟)。
嫌它碍事可以在设置里关掉。
判定是离线的
用插件内置的规则引擎判目标境内外,不发任何网络请求。所以它不会被网络状况影响,判定结果和 dsh_download 走的是同一套规则。
装完要重启
dsh plugin --profile desktop add https://github.com/having5548/dsh-downloader/releases/latest/download/having5548-dsh-downloader-0.3.0.tgz宿主对已加载模块有 ESM 缓存,remove+install 只更新磁盘。
质量
node test/smoke.mjs → 250 passed, 0 failed(上一版 225)。新增:URL 提取与去重、七类判定(境外 / 境内 / 回环 / 内网 / SSH / 已带代理 / REJECT)、pwsh 与 bash 前缀生成、代理 URL 组成、dsh_run_proxied 的两种渲染。
MIT。内核部分派生自 dsh-clash-proxy 0.2.0(MIT),各文件头部保留出处。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。
v0.2.1 — 配置列表与状态渲染的两处文案
dsh-downloader v0.2.1 — 两处渲染文案
| 位置 | 之前 | 现在 |
|---|---|---|
dsh_profile 列表 |
未选中的配置显示 ? 个节点 |
只在当前配置上显示节点数(其余本来就没解析过) |
dsh_proxy_status |
有配置时仍打印「订阅地址 | proxyUrl | 启动环境代理」 | 只留一行「旧版单条订阅地址:已填(当前不生效,被上面的配置覆盖)/ 未填」;没有配置时才输出完整三字段 |
原因:这两处文案是 0.1.x 单条 subscriptionUrl 模型下写的,0.2.0 引入多份配置后没跟着改。
本版仅修文案,无功能与行为改动。 测试 224 → 225 passed, 0 failed。
安装
dsh plugin --profile desktop add https://github.com/having5548/dsh-downloader/releases/latest/download/having5548-dsh-downloader-0.2.1.tgz装完重启 DSH(宿主对已加载模块有 ESM 缓存,remove+install 只更新磁盘)。
MIT。内核部分派生自 dsh-clash-proxy 0.2.0(MIT),各文件头部保留出处。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。
v0.2.0 — 节点导入对齐 FlClash + 代理只服务 DSH 自身下载
dsh-downloader v0.2.0 — 节点导入对齐 FlClash + 代理作用域收紧
一、节点导入对齐 FlClash
参考了 example/FlClash-main 的 Profile 模型与 ProfilesAction:FlClash 把配置存成一份列表,每份要么是订阅 URL、要么是导入的本地文件,各自带名字、上次更新时间与自动更新间隔。这一版按同一模型实现。
三种导入入口(面板「节点配置」卡片,或让模型调 dsh_profile):
| 入口 | 说明 |
|---|---|
| 从订阅地址 | 粘贴 https://…,或直接粘 FlClash / Clash Verge 那种 clash://install-config?url=… 深链(自动取出里面的地址) |
| 从文件导入 | 选一个本地 .yaml / .yml 配置 |
| 交给模型 | 「把这个订阅导入:…」→ dsh_profile 工具 |
按 FlClash 的规则取名:先取响应头 Content-Disposition 里的文件名,再退回域名。流量与到期取自 subscription-userinfo(upload/download/total/expire),面板与工具返回里都会显示。
每份配置独立:自己的自动更新开关与间隔(默认 24 小时);本地文件配置永不自动更新(对应 FlClash 的 realAutoUpdate);到点判断用 lastUpdateDate + autoUpdateDuration,由 5 分钟一次的扫描驱动,而不是全局统一节拍。
支持 选择 / 更新 / 删除 / 改名 / 排序。
存放位置:$DSH_HOME/dsh-downloader/profiles.json + profiles/<id>.yaml(原子写入)。
旧的单条
subscriptionUrl配置保留为回退:没有任何配置时才走它,既有安装不受影响。
二、代理作用域:只服务 DSH 自己发起的下载
这不是靠约定,而是三重硬约束:
| 约束 | 效果 |
|---|---|
只绑 127.0.0.1 |
局域网内其它机器根本连不上 |
| 每进程随机令牌(24 字节,只活在进程内,不落盘不写日志) | 没有令牌的 HTTP 连接一律 407;SOCKS5 握手装不下令牌,直接拒绝 |
| 不碰系统代理、不写环境变量 | 浏览器、其它 App、DSH 里非本插件的出网请求全部保持原样 |
dsh_proxy_status 的 scope 字段如实报告这三条,面板「上游」卡片也写出来。就算端口被扫到也用不了;除 dsh_download 外的任何流量从未经过它。
安装
dsh plugin --profile desktop add https://github.com/having5548/dsh-downloader/releases/latest/download/having5548-dsh-downloader-0.2.0.tgz装完重启 DSH(宿主对已加载模块有 ESM 缓存)。
质量
node test/smoke.mjs → 224 passed, 0 failed(上一版 171)。新增:配置存储往返、clash:// 深链与 subscription-userinfo 解析、文件名起名、自动更新到期判定,以及令牌鉴权的三条路径(带令牌成功 / 无令牌 407 / SOCKS5 被拒)。
MIT。内核部分派生自 dsh-clash-proxy 0.2.0(MIT),各文件头部保留出处。仅提供技术能力,请确保你的代理服务与使用方式符合当地法律法规。