Files

3.2 KiB
Raw Permalink Blame History

dsh-local-403-fix

修复 dsh web 反向代理访问时特权 /api 方法返回 403 的问题。

背景

官方 @deepseek-ai/dsh-client-connection 把 15 个特权方法(settings.*credentials.*agentPreset.*host.pickDirectory/openPathllm.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 历史或脚本注释)。