带密码的 DSH 局域网网关,手机连同一个 WiFi 就能用浏览器打开电脑上的 DSH;不改 DSH 自身文件,但会向发给手机的页面注入一小段兼容 polyfill。明文 HTTP,仅限可信局域网。
安装
# npm 包(预构建)
dsh plugin --profile web add @realoiyo/dsh-web-gate
# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)
dsh plugin --profile web add github:REALOIYO/dsh-web-gate
装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本——pnpm 默认拦截,所以安装可能停在 ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED 或 ERR_PNPM_IGNORED_BUILDS;dsh 会打印出需要添加的确切键名,把它加进该 profile 的 pnpm-workspace.yaml 的 allowBuilds 下,重跑一次即可装上。放行构建本身就是一次信任判断:请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。
README
为 DeepSeek Harness 提供带密码认证的局域网网关。同一网段内的设备可通过浏览器访问运行在桌面端的 DSH 实例。
不修改 DSH 界面。仅注入一段 polyfill——非安全上下文下写入路径不可用,见下文。
背景
dsh --profile web 只监听 loopback。官方反代方案(--public-url + --trusted-host)不适用于桌面版:
- Host 由 Electron 拉起,无法追加命令行参数;
- 端口每次启动动态分配,无法预先写入反代配置;
- 根路径需携带仅存在于进程内存中的
?token=才能换取会话 Cookie。
网关因此实现在 Host 进程内,可直接读取 ctx.webServer.port 与 ctx.connection.authenticatedUrl()。
安装
从 npm 安装:
dsh plugin --profile desktop add @realoiyo/dsh-web-gate
也可以从 GitHub 直接装(会走源码构建):
dsh plugin --profile desktop add github:REALOIYO/dsh-web-gate
安装后重启 DSH。监听地址与密码写入日志,同时显示在 设置 → 手机网关(支持复制与改密)。客户端与主机处于同一网段时,浏览器访问 http://<主机局域网IP>:3082 并输入密码。
配置
配置文件为 $DSH_HOME/dsh-web-gate/settings.json,修改后重启生效。
| 键 | 默认值 | 说明 |
|---|---|---|
port |
3082 |
监听端口 |
host |
"0.0.0.0" |
监听地址 |
password |
随机 10 位 | 访问密码,最少 8 位,可在设置页自定义 |
secret |
随机 32 字节 | 会话签名密钥,修改将使全部会话失效 |
优先级:profile patch 中的 config > settings.json > 随机生成。
会话 Cookie 由 HMAC(secret, password) 派生,因此改密等同于注销全部已登录设备。
实现
token 握手。 网关先在内部以 launch token 请求 / 并取得会话 Cookie,再转发外部请求,客户端不会观察到 303。
上游 Cookie 拦截。 DSH 的认证 Cookie 名为 dsh-auth-<sha256(host:port)>,含端口成分;桌面版每次启动端口变化且不清理旧 Cookie,条目持续累积。累积至 71 个时 Cookie 头约 16.4 KB,触及 Node 的 16 KB 请求头上限,返回 HTTP 431,表现为 DSH 报「Web authentication failed」而无法启动。网关拦截全部上游 Set-Cookie,仅在内存中保留当前一个;客户端侧只存在 dsh_gate_session。
polyfill 注入。 客户端经 http://<局域网IP> 访问时,两个前提不成立:
- 非安全上下文:
crypto.randomUUID为undefined,而 DSH 连接层用它生成 connectionId / sessionId / messageId;AbortSignal.any在部分浏览器亦缺失。缺失时表现为可读不可写。 - hostname 非回环:DSH 将设置持久化方式绑定于该判定(
isLoopback ? 'host' : 'memory'),镜像退化为内存模式,写入不落后端,界面持续提示无法保存。
注入仅在 API 缺失时执行,不覆盖原生实现,以 data-dsh-gate-polyfill 属性判重。文本注入要求响应体未压缩,故文档请求移除 accept-encoding;JS / CSS / 字体保持压缩。
安全
- 密码为唯一凭证。网关可在主机上执行代码,凭据不应外传。
- 登录限速:单 IP 每分钟 5 次失败锁定 60 秒,全局每分钟 50 次失败锁定 30 秒。会话 Cookie 为
HttpOnly+SameSite=Lax,校验使用常量时间比较。 - 流量为明文 HTTP,同网段可嗅探密码,仅应在可信局域网内使用。跨网络部署需叠加 WireGuard / Tailscale 等隧道,不应直接暴露公网。
- 密码以明文存于
settings.json(0600)用于派生会话密钥,同机其他管理员账户可读。
限制
- 不提供公网隧道与移动端适配。
- 不生成二维码(安装
qrcode-terminal时输出)。 - WebSocket 认证仅在握手阶段校验一次,与浏览器直连行为一致。
Host/Origin/Referer/Sec-Fetch-Site统一改写为 loopback。若部署依赖真实 Host,需相应调整。
开发
node --test test/*.test.js
共 60 项测试。test/proxy.test.js 启动真实 HTTP 服务并以假上游模拟 DSH 的 401 / 303+Cookie / 200 响应,覆盖握手、头改写、Cookie 卫生与限速;test/inject.test.js 实际执行注入脚本,验证 polyfill 生成的 UUID 符合 RFC 4122、原生实现存在时不覆盖、transport shim 在宿主先赋值与后赋值两种时序下均生效。
License
MIT
链接
同类插件
zhu1090093659/dsh-web#packages/dsh-remote-web-ui★ 9959
手机/PC 远程操控 dsh web 工作区:扫码配对、令牌门控通道、SSE 实时同步,提供移动端与完整桌面 GUI 两种远程形态。
zhu1090093659/dsh-web#packages/dsh-ssh★ 9959
SSH 远程运维面板:Web 终端、SFTP 传输、本地端口转发与一条命令并发集群执行,Agent 与面板共用同一份主机配置。
liguobao/ds-harness-remote★ 1319
通过端到端加密通道远程访问 DeepSeek Harness 及兼容的编码工作区,支持自适应 Relay/WebRTC 传输、设备授权、工作区文件、只读预览、终端和可选的 Codex Remote。
saya-ch/dsh-mobile★ 728
通过 Android App 或手机浏览器访问 DeepSeek Harness,支持安全局域网连接、远程访问、持久设备配对和可自定义移动界面。
uumit-ai/dsh-uumit-remote★ 381
用 UUMit 账号在手机或其他电脑上打开这台电脑的 dsh web,不用自建服务器、不装其他程序:插件内置通道客户端连接 UUMit 托管的通道,侧栏里的面板负责配对和选择谁能用(仅自己、通过邀请链接或手机号授权的人、所有人),可随时撤销。需 dsh web 且 DSH >=0.2.1-rc.2。
ZSeven-W/dsh-ios★ 355
在对话里直接操作 iOS 模拟器或 USB 连接的 iPhone:22 个 Agent 工具用于启动、构建、按无障碍标识或 OCR 文本驱动 UI、列表行操作与 SwiftUI 预览热重载,并附带可点击拖拽的流式侧边栏面板。
社区评论
评论公开保存在 GitHub Discussions。加载评论会连接 GitHub 和 Giscus;发表内容需要 GitHub 账号。