3.2 KiB
dsh-local-403-fix
修复 dsh web 反向代理访问时特权 /api 方法返回 403 的问题。
背景
官方 @deepseek-ai/dsh-client-connection 把 15 个特权方法(settings.*、credentials.*、
agentPreset.*、host.pickDirectory/openPath、llm.discoverModels)钉死在 loopback:
前缀路由先用配置的 trustedHosts 校验,但进入 fetch handler 后,这些方法会用空列表
再校验一次:
// dsh-client-connection@0.1.0-rc.7 lib/index.js 第 538 行
if (method !== void 0 && PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, []))
return new Response("forbidden", { status: 403 });
因此即使 --trusted-host 配置了公网域名/IP,任何经过反向代理(本环境为
Xray 隧道 + socat)到达的请求,只要 Host 头不是 loopback,特权方法一律 403。
这是官方刻意设计(配置/凭据平面在"真正的认证层出现之前"保持 loopback 同源),
上游 master 至今未改(packages/client/connection/src/index.ts 第 147 行)。
方案(本目录采用一行补丁,替代旧的 260 行插件)
对运行时实际加载的全局包打一行补丁,把特权检查的空列表换成配置的 trustedHosts:
- if (method !== void 0 && PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, [])) return new Response("forbidden", { status: 403 });
+ if (method !== void 0 && PRIVILEGED_METHODS.has(method) && !isTrustedApiRequest(request, trustedHosts)) return new Response("forbidden", { status: 403 });
语义与上游一致:trustedHosts 仍是 DNS-rebinding 围栏,不是认证层。
trustedHosts 变量在 apply() 作用域内(第 531 行),补丁无需额外改动。
文件
| 文件 | 作用 |
|---|---|
patches/@deepseek-ai+dsh-client-connection@0.1.0-rc.7.patch |
标准 pnpm 补丁(进 git,可复现) |
apply-403-fix.sh |
幂等脚本:定位全局包 → 备份 → patch -p1 应用/回滚/检查 |
package.json |
pnpm.patchedDependencies 声明(工程内 pnpm install 时自动应用) |
cordis.patch.yml + src/index.js |
⚠️ 旧方案(260 行插件 bundle),已由本补丁替代,保留仅供回退参考 |
用法
# 应用补丁(幂等;my_deepseek.sh 启动前会自动调用)
./apply-403-fix.sh
# 检查状态
./apply-403-fix.sh --check
# 回滚
./apply-403-fix.sh --revert
应用后重启 dsh 生效:
my_deepseek.sh stop && my_deepseek.sh
为什么不用 pnpm patchedDependencies 直接生效?
pnpm.patchedDependencies 只对当前 pnpm 工程的依赖树生效;而本环境的 dsh 是
全局 npm 安装(/home/salmonstill/.nvm/.../lib/node_modules/@deepseek-ai/dsh),
运行时加载的是全局那份 dsh-client-connection。所以工程内保留标准补丁文件 +
apply-403-fix.sh 幂等打到全局包,两者兼顾可复现与运行时生效。
将来若把 dsh 改为工程内安装,patchedDependencies 声明可直接复用。
升级 dsh 后
apply-403-fix.sh --check会显示unknown(特权检查行已变),此时需对照新版 源码更新补丁文件;- 补丁文件内的 blob hash 需用
git hash-object重新计算(见 git 历史或脚本注释)。