Files

76 lines
3.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 历史或脚本注释)。