# 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 后,这些方法会**用空列表 再校验一次**: ```js // 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`: ```diff - 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),已由本补丁替代,保留仅供回退参考 | ## 用法 ```bash # 应用补丁(幂等;my_deepseek.sh 启动前会自动调用) ./apply-403-fix.sh # 检查状态 ./apply-403-fix.sh --check # 回滚 ./apply-403-fix.sh --revert ``` 应用后重启 dsh 生效: ```bash 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 历史或脚本注释)。