Skip to content

fix(rpc): 修 requestRejection 丢失 this 绑定致 /dsh-pocket/* 全部 403(issue #117) - #118

Merged
shaobeichen merged 1 commit into
shaobeichen:mainfrom
qgx1992:fix/requestrejection-this-binding
Sep 10, 2026
Merged

shaobeichen merged 1 commit into
shaobeichen:mainfrom
qgx1992:fix/requestrejection-this-binding

Conversation

@qgx1992

@qgx1992 qgx1992 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

问题

DSH 0.1.5-rc.1 + dsh-pocket 2.10.4 下,插件路由 /dsh-pocket/* 全部返回 403:

  • 设置 → 手机访问 →「局域网访问」永远停在 代理未就绪…,二维码始终不显示(代理本身是好的)
  • 点「开启公网访问」约 76 秒后报 transport failure for /dsh-pocket/tunnel.start: HTTP 403

Fixes #117(该报告者的定位与本文一致,我独立复现并给出了回归测试)。

根因

lib/web-rpc.js 的 mountPocketWebRoute() 把方法从 ctx.connection 上抽成裸函数再调用:

const requestRejection = ctx?.connection?.requestRejection;
...
try { rejection = requestRejection(req); } catch { rejection = 403; }   // this === undefined

而 dsh 的实现是依赖 this 的类方法:

// @deepseek-ai/dsh-client-connection/lib/index.js
requestRejection(request) {
  if (!isTrustedApiRequest(request, this.trustedHosts)) return 403;   // this.trustedHosts -> TypeError
  return this.browserAuth.isAuthenticated(request) ? void 0 : 401;
}

裸调用时 this === undefined → 读 this.trustedHosts 抛 TypeError → 被 catch 一律归一成 403。
结果:本机、带会话 cookie 的浏览器、移动端的所有请求都进不来,本该 401 的也变 403。

为什么 alpha 版没暴露:该方法的 0.1.5-alpha.1 实现不依赖 this(或以不同方式依赖),rc.1 改为读取
this.trustedHosts / this.browserAuth 后才触发。

修改

-  const requestRejection = ctx?.connection?.requestRejection;
+  const connection = ctx?.connection;
...
-      if (typeof requestRejection === 'function') {
-        try { rejection = requestRejection(req); } catch { rejection = 403; }
+      if (typeof connection?.requestRejection === 'function') {
+        try { rejection = connection.requestRejection(req); } catch { rejection = 403; }

以方法形式调用,与 dsh 自己的 /api 路由写法一致(client-connection 的 register() 里就是
this.requestRejection(req));等价于 #117 报告者建议的 requestRejection.call(ctx.connection, req)。

旁证:本仓库 lib/index.js 处理 authenticatedUrl 时原本就是 fn.call(ctx.connection, ...)——
说明该绑定约定作者已知,唯独 requestRejection 这里漏了。

验证(真机对照)

Windows 10 / Node 24 / DSH 0.1.5-rc.1 同一台机器:

请求 修复前 修复后
POST /api(dsh 自带,方法调用) 401 / 403 正常分化 —
POST /dsh-pocket/pocket.status 恒 403 forbidden 200 + 完整 status JSON

修复后 pocket.status 正常返回:

{ "proxyRunning": true, "proxyPort": 3081, "lanUrl": "http://10.10.0.172:3081",
  "tunnelRunning": false, "dshPort": 53475, "lanEnabled": true, "lanAuthEnabled": true }

(局域网二维码 lanQr 也正常生成)设置页恢复正常,手机扫码可用。

测试

  • 新增回归用例(test/webserver-mount.test.js):用与 dsh 同构的「类方法 + 依赖 this」的 fake
    connection 覆盖 —— 修复前验证其失败(403)、修复后通过(200)。
  • node --test test/webserver-mount.test.js → 17/17 通过。
  • 全量 npm test 在本机 Windows 为 169/171,另 2 个失败来自 test/tunnel-args.test.js 的
    Windows 平台固有限制(假 cloudflared 是无扩展名的 shebang 脚本,Windows spawn 报 ENOENT,
    Linux/macOS 下正常),与本次改动无关,本 PR 未触碰该文件。

…haobeichen#117)

dsh 0.1.5-rc.1 的 HostConnectionService.requestRejection 是依赖 this 的类方法
(内部读 this.trustedHosts / this.browserAuth)。mountPocketWebRoute 把方法从
ctx.connection 上抽成裸函数后再调用,this 丢失 → TypeError → 被
`catch { rejection = 403 }` 吞成 403,于是本机 / 带会话 cookie 的浏览器 / 移动端
的**所有** /dsh-pocket/* 请求恒为 403:

  - 设置页 pocket.status 全挂 → 局域网区块卡在「代理未就绪…」、二维码始终不显示
  - 公网隧道 tunnel.start 报 transport failure for /dsh-pocket/tunnel.start: HTTP 403

改为以方法形式调用(connection.requestRejection(req)),与 dsh 自己的 /api 路由
(client-connection 的 register())一致;等价于 issue shaobeichen#117 报告者建议的
requestRejection.call(ctx.connection, req)。

回归测试:test/webserver-mount.test.js 新增用例,用与 dsh 同构的「类方法 + 依赖
this」的 fake connection 覆盖。已在修复前验证其失败(403),修复后通过(200)。

Refs shaobeichen#117
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 2.10.5 🎉

The release is available on:

Your semantic-release bot 📦🚀

@qgx1992
qgx1992 deleted the fix/requestrejection-this-binding branch September 10, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] DSH 0.1.5-rc.1:requestRejection 丢失 this 绑定 → /dsh-pocket/* 全部 403(局域网二维码不显示、公网隧道无法启动)

2 participants