dsh-remote-control
DiscoveredA plugin help you control the dsh from remote (you need to setup your own network by tailscale or zerotier)
dsh-remote-control
给手机开一个进入本机 Harness 的入口:一个永久密码,一次设置,长期免密。地址、端口、密码、设备全部在「设置 → 远程控制」里管,即时生效、重启后仍在。
不负责隧道:dsh web 保持回环绑定、零参数启动;跨网络可达性由你自己的 Tailscale / ZeroTier / 局域网解决。本插件只在你能路由到的那个地址上开一个入口。
手机 ──http://100.x.y.z:3080──▶ [本插件入口:密码门 + 设备会话]
│ ① 没有会话 → 自己的登录页
│ ② 密码正确 → 发会话 Cookie(滑动 180 天)
▼
反向代理(改写 Host/Origin,注入服务端凭据)
▼
127.0.0.1:3080 ← Harness 本体,原样不动
为什么是"反向代理 + 密码门"
Harness 本体只有一条认证路径:启动令牌 → 签发的 dsh-auth-* Cookie。它没有密码这个概念,而 /api 与 WebSocket 升级都只认那个 Cookie。要在不改 Harness 的前提下加"永久密码",就必须有一个"请求到达 Harness 之前"的地方来校验——那就是本插件的入口监听器,它接请求、验密码、再转发给回环上的 Harness。这个角色就是反向代理。
关键设计:Harness 的凭据由服务端代持。插件启动时用公开 API 换一次 Harness Cookie 存在内存里(ctx.connection.authenticatedUrl()),转发时注入、并把 Harness 返回的 Set-Cookie 全部丢弃。手机永远拿不到 Harness 凭据,只持有本插件的会话 Cookie——所以"下线这台设备"是真的下线:删会话、掐断它的 HTTP 与 WebSocket。
能力
入口与会话
- 在设置页从本机网卡里挑一个地址(
100.64/10标为 Tailscale、私网段标为内网),设端口,点「应用」即生效;换地址是新地址先绑定成功才关旧地址,失败不动现有配置。 - 拒绝通配地址(
0.0.0.0/::):那会同时打开所有网卡。允许allowFromCIDR 白名单,例如只放行100.64.0.0/10。 - 永久密码:scrypt(N=16384) 存哈希,至少 8 位;改密码即轮换签名密钥,所有设备重新登录。
- 一次性邀请码:6 位无歧义码、10 分钟、单次使用,交给临时使用的人;状态文件只存 SHA-256。
- 设备会话台账:名称、来源地址、登录/活跃时间、登录方式(密码/邀请),可重命名、单台下线、全部下线。会话 180 天滑动续期。
- 登录限速:每地址每分钟 5 次,连续失败指数退避至 15 分钟,失败与密码错误统一文案。
传输与移动端
- HTTP 流式透传:上传(拖文件、附件)、SSE 长响应都不缓冲;WebSocket(
/api/remote.mux)按原始字节双向管道,实时消息照常到手机。 - 窄屏样式(iOS 输入框 16px 防缩放、安全区、触摸目标)由 Host 注入,全部包在媒体查询里,桌面布局零影响。
- 页面回到前台时主动重连:手机息屏后 socket 静默死亡,这是浏览器侧唯一可靠的修复点。
安装与使用
# 用安装工具落盘(不要手写 profile 的 package.json / cordis.patch.yml)
plugin_manager action=install_bundle target=/绝对路径/dsh-remote-control
-
照常启动 Harness(不需要任何参数,保持默认回环绑定):
dsh web -
设置 → 远程控制:
- 「监听地址」选 Tailscale 地址(如
100.101.102.103)或局域网地址,端口默认3080; - 设「永久密码」;
- 打开「开启入口」→ 应用。成功后卡片上给出入口地址。
- 「监听地址」选 Tailscale 地址(如
-
手机(同一 tailnet / 同一局域网)打开该地址,输入密码即可。之后长期免密,除非你下线该设备或改密码。
-
临时借用:生成一次性邀请码,让对方用码登录(不需要密码),用完可随时下线。
端口说明:
dsh web在127.0.0.1:3080,入口在100.x:3080,不同地址不冲突。桌面版的 Harness 端口由系统分配,插件会自动跟随。若你把 Harness 也绑到了同一个地址,应用时会报EADDRINUSE,把入口换成别的端口即可。
桌面版(DSH Desktop)
插件同样适用于 DeepSeek Harness 桌面版。桌面版是 Electron 外壳 + 同一个 Harness 运行时,插件在其中的行为与 dsh web 一致,只有两点差别:
- 装到桌面版自己的 profile:桌面版使用
~/.dsh/profiles/desktop,要在桌面版窗口内的插件管理器里安装;CLI 的安装命令装的是 web profile。 - Harness 每次启动换端口和令牌:插件跟随
webServer.getOrigin()取上游,origin 变化时自动重新换取凭据;WebSocket 升级遇到 401 会刷新凭据并重试一次。所以桌面版重启后手机页面会自行恢复,不用重装、也不用重设密码。
安装步骤:
- 桌面版打开插件管理器 → 安装本地路径(本仓库目录)或 npm 包
@blake_john/dsh-remote-control; - 重启桌面版(插件行在启动时加载);
- 「设置 → 远程控制」设永久密码、选监听地址、打开入口,手机按同样方式访问。
桌面版与
dsh web共用~/.dsh/remote-control/state.json(密码、设备台账互通)。如果两个都装并且同时运行,给它们设不同的入口端口即可。
安全边界
| 事项 | 结论 |
|---|---|
| 传输加密 | 入口是明文 HTTP,依赖 tailnet(WireGuard)或局域网本身。若需 HTTPS,见路线图;当前不要把它暴露到公网。 |
| 密码强度 | 等于本机权限,务必用长密码;插件只存 scrypt 哈希,日志不记密码、不记邀请码明文。 |
| 手机持有的凭据 | 只有本插件的会话 Cookie(HttpOnly / SameSite=Strict)。Harness 的 Cookie 不下发。 |
| 下线强度 | 撤销即断:会话校验失败 → 登录页;该会话的活跃 HTTP/WebSocket 全部 destroy。改密码/全部下线同时轮换签名密钥。 |
| 遗忘密码 | 本机桌面(回环直连)随时可进设置页重设,无需找回流程。 |
| 开放代理风险 | 目标写死为本机 Harness,绝不按请求头路由;拒绝通配绑定。 |
| 登录端点 | 仅同源 POST;跨站 Origin 直接 403;限速 + 冷却。 |
测试与验证
node --test tests/*.test.mjs # 56 条:逻辑单测 + 真实 socket 的端到端 + 浏览器半静态守卫
node --check index.js client.js lib/*.js
端到端用例覆盖:未设凭据拒绝开启、通配地址拒绝、绑定与 URL 上报、登录页、错密码/对密码、代理头改写与凭据替换、2MB 上传流式、SSE 分段到达、WebSocket 隧道双向、无会话升级被拒、白名单 403、部分字段的 apply 不清空白名单、撤销并掐断活跃 socket(含进行中的 HTTP 流)、改密码强制全下线、邀请码单次有效、坏 CIDR 拒绝、关闭入口、限速冷却,以及桌面版重启(换端口后重取凭据、令牌轮换后 WebSocket 升级重试)。
安装后确认
ls ~/.dsh/remote-control/state.json # 出现即表示已挂载
curl -s -o /dev/null -w '%{http_code}\n' -X POST \
-H 'content-type: application/json' \
-d '{"type":"client-request","rpcId":"p","method":"ping","payload":{}}' \
http://127.0.0.1:3080/remoteControl/ping # 期望 401(路由存在、未带凭据)
然后在浏览器「设置 → 远程控制」里:选监听地址(Tailscale 的 100.x)→ 设永久密码 → 打开开关 → 应用;手机打开卡片上的入口地址输密码即可。
路线图
- HTTPS 入口:设置页填证书/私钥路径,会话 Cookie 自动加
Secure。 - 二维码:把入口地址渲染成二维码,省掉手机手输。
- 多入口:同时监听多个地址(局域网 + tailnet),每个地址独立白名单。
- TOTP 二次验证 与 会话有效期可配(含"永不过期")。
- 非 owner 权限分级:把设备接进
PrincipalMap/remoteAccess角色体系,实现"只能看会话、不能改设置"。
设计取舍见 docs/design.md;真机验收记录见 docs/acceptance.md。
开发与发布
npm run check # 清单一致性 + 54 条测试(等价于 CI)
git push origin main # 触发 ci.yml
git tag -a v2.1.0 -m "…" && git push origin v2.1.0 # 触发 publish.yml → npm
细节(认证方式、可信发布、首次发布注意)见 docs/publishing.md。
License
Apache-2.0 —— 见 LICENSE。
Comments
Loading…
Similar plugins
Manage your own remote DSH host from the local GUI: SSH tunnels, mixed remote session list, one-click remote GUI, auto-healing tunnels.
★ 136
↓ 36/wk
MIT
JavaScript
dsh plugin --profile web add dsh-sevDSH plugin: password SSH into a remote host — a natural-language tool (connect/exec/close/status) over a persistent ControlMaster session, plus a browser terminal panel (right-side floating) with a real PTY over WebSocket.
★ 0
dsh plugin --profile web add dsh-ssh-shellby mazov2love
给dsh像user一样以后端逻辑操控另一个本机dsh实例的能力
★ 3
MIT
JavaScript
Oct 28, 2026
dsh plugin --profile web add @mazov2love/dsh-remote-controlby ImHaoYuan
DSH 插件:搭建远程控制局域网服务器,手机浏览器直连,也可下载App
★ 0
MIT
JavaScript
Oct 10, 2026
dsh plugin --profile web add dsh-mobile-mirrorby Mzy123l
为 DeepSeek Harness 桌面版提供「限网段 + 可选数字密码」的远程访问入口
★ 4
MIT
JavaScript
Oct 18, 2026
dsh plugin --profile web add dsh-plugin-remote-accessby androidly
Adds a restart control at the DSH Web sidebar foot: the host exits through its own graceful path and the detected supervisor (systemd, Kubernetes or Docker) boots the replacement, or the plugin starts
★ 0
MIT
JavaScript
Oct 22, 2026
dsh plugin --profile web add dsh-restart-control