🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

手机链路管理 ArimaKana-Akane/dsh-sakurafrp

DeepSeek Harness
ArimaKana-Akane51 天前有提交已提供中文文档扫描:含敏感能力

在会话头部管理手机隧道,扫码配对并自愈网关

29.7/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/16 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add ArimaKana-Akane/dsh-sakurafrp
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · ui
装得上吗
本站已真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 51 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

未发布到 npm registry,仅可从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-sakurafrp(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=20 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/9/21 23:54:39

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令写入剪贴板(不计风险)读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 7 处,展示前 7 条)
  • 读取密钥环境变量
    lib/index.js:106
    const ADMIN_TOKEN = String(process.env.DSH_SAKURA_ADMIN_TOKEN || '')
  • 发起网络请求
    lib/index.js:215
    const res = await fetch(url, init)
  • 发起网络请求
    lib/index.js:232
    req = https.request({
  • 执行外部命令来自配置/变量
    lib/index.js:330
    const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'] })
  • 发起网络请求
    lib/client.js:89
    const res = await fetch(API + path, init);
  • 写入剪贴板
    lib/client.js:142
    await navigator.clipboard.writeText(text);
  • 发起网络请求
    lib/client.js:324
    fetch(API + '/qr.svg?t=' + encodeURIComponent(String(lastPair.at || Date.now())), {
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 管理手机隧道连接
  • 扫码配对设备
  • 网关自愈

dsh-mobile 卫星:在 DSH 界面管理 SakuraFrp 手机与桌面的连接(状态、网关开关、配对二维码、设备、自愈)。凭感觉写的。

README

由 DeepSeek 最新模型翻译生成
dsh-sakurafrp [!WARNING] 本仓库是 vibe coding 产物。 代码由作者与 AI(DeepSeek Harness 会话)对话生成、多轮迭代而来,没有经过人工逐行审计,也只在作者本机环境(WSL2 + dsh 0.1.5-rc.1 系列)实测过。请自行审阅后再使用;不要直接用于生产或安全敏感场景。 代码按 MIT「按原样(AS IS)」提供,不附带任何担保,风险自负。 一个为 dsh-mobile 打造的 vibe coding 卫星插件:完全在 DSH 自己的 UI 中管理手机 ↔ 桌面链路(SakuraFrp TCP 隧道 + dsh-mobile 网关)——状态、网关开关、一次性配对二维码、设备撤销、自愈。 把「手机通过 SakuraFrp 隧道访问电脑上的 DSH」这条链路图形化:原先要跑脚本、改 YAML、盯 systemd 才能完成的事,现在在 DSH 会话头部点一个手机图标就能做。
展开完整文档(README 剩余 1 节)
dsh-sakurafrp

[!WARNING]
本仓库是 vibe coding 产物。 代码由作者与 AI(DeepSeek Harness 会话)对话生成、多轮迭代而来,没有经过人工逐行审计,也只在作者本机环境(WSL2 + dsh 0.1.5-rc.1 系列)实测过。请自行审阅后再使用;不要直接用于生产或安全敏感场景。
代码按 MIT「按原样(AS IS)」提供,不附带任何担保,风险自负。

一个为 dsh-mobile 打造的 vibe coding 卫星插件:完全在 DSH 自己的 UI 中管理手机 ↔ 桌面链路(SakuraFrp TCP 隧道 + dsh-mobile 网关)——状态、网关开关、一次性配对二维码、设备撤销、自愈。

把「手机通过 SakuraFrp 隧道访问电脑上的 DSH」这条链路图形化:原先要跑脚本、改 YAML、盯 systemd 才能完成的事,现在在 DSH 会话头部点一个手机图标就能做。

1. 它做什么

| 能力 | 说明 |
| 链路状态一屏可见 | 网关是否在跑、监听端口、公网入口、四个公网节点的实测延迟、已配对设备数、外部守护服务状态 |
| 一键开关手机访问 | 直接控制 dsh-mobile 的移动网关(等价于 POST /api/mobile-access/lan/control);关闭会留下抑制标记,自愈不再把它拉回来 |
| 配对二维码 | 申请一次性配对窗口(默认 5 分钟有效),二维码与链接内联返回,手机相机/浏览器扫码即可 |
| 设备管理 | 逐台撤销、一键清空(清空会带上游要求的 confirm:true);配合 maxDevices 实现「只信任某一台设备」 |
| 网关自愈 | 每 15 秒检查移动网关,发现被静默关闭(已知问题)就重新拉起 —— 但用户主动关闭时让路(见下方说明) |
| 公网可达性探测 | 每 60 秒并发探测主入口 + 三个运营商前缀节点,面板直接显示谁通谁不通 |
| 外部守护开关 | 可启停 dsh-mobile-lan-watchdog.service(冗余层,插件自带自愈已能独立兜底;它同样尊重「用户已关闭」标记) |

「关得掉」是硬要求。 早期版本的自愈是无条件的:你关掉手机访问后,15 秒内它就会被自动拉起来,连 dsh-mobile 自己持久化的 enabled:false 偏好也一并被覆盖——表现为「根本关不掉」。现在点「关闭手机访问」会写一个抑制标记(默认 $DSH_HOME/mobile-access/.gateway-user-disabled),插件自愈与外部 watchdog 都会跳过;面板也会显示「你已主动关闭…」。点「开启手机访问」即删除标记、恢复自愈。

入口:DSH 会话头部工具区的手机图标按钮(order: -15,位于「重启」与「打开文件管理器」之间)。
手机端也能打开这个面板,但只能看状态(原因见第 6 节)。

2. 依赖声明(重要)

2.1 运行期硬依赖:dsh-mobile 插件

本插件不自己实现任何网关,它只是 dsh-mobile 的移动访问网关的图形化管理壳。
没有 dsh-mobile 时:/status 会显示网关无响应,/pair 会报「网关未启动或 dsh-mobile 未启用」。

它依赖 dsh-mobile 提供的这些本机(loopback)管理接口:

| 方法 | 路径 | 用途 |
| GET/POST | /api/mobile-access/lan/control | 网关开关({running: bool}) |
| GET | /api/mobile-access/lan/status | 网关/配对/设备数/资源占用 |
| GET | /api/mobile-access/lan/devices | 设备列表 |
| POST | /api/mobile-access/lan/devices/revoke | 撤销设备({deviceId},32 位小写 hex) |
| POST | /api/mobile-access/lan/devices/reset | 清空设备 |
| POST | /api/mobile-access/lan/pairing/open | 申请一次性配对窗口,返回 pairUrl + qrSvg |

2.2 运行期硬依赖:SakuraFrp 隧道(非 npm)

公网入口由 SakuraFrp 启动器常驻的 frpc 提供。本插件不启动、不配置、也绝不接触访问密钥。
面板预建一条 TCP 隧道,并且:

- 隧道远程端口必须等于 profile 里 mobile-access.listenPort(插件硬约束:显式 authority 的端口必须等于监听端口);
- 隧道不要设置「访问密码」——那会让 frpc 接管 TLS 去渲染认证页,破坏端到端自签证书与 Host 校验;
- Windows 端 frpc 经 WSL2 networkingMode=mirrored 的 localhost 直通,回连 WSL 回环监听。

2.3 运行期软依赖

| 项目 | 必需 | 用途 |
| dsh-mobile-lan-watchdog.service(本仓库 scripts/dsh-mobile-lan-watchdog.sh) | 否 | 网关被静默关闭时的第二层自愈;插件自带 15s 自愈已可独立兜底 |
| systemctl --user | 否 | 外部守护服务的启停 |

2.4 平台与版本

| 项目 | 要求 |
| 操作系统 | Linux / WSL2(插件用 systemctl --user、路径按 POSIX 拼) |
| Node | >= 20(用到全局 fetch、AbortSignal.timeout) |
| dsh 核心 | 在 0.1.5-rc.1 系列的 web profile 上验证;其它版本自测 |
| dsh profile | web($DSH_HOME/profiles/web) |

2.5 dsh-dependencies 声明

除 README 外,package.json 里也带了机器可读的声明:

"peerDependencies": { "dsh-mobile": "" },
"dshDependencies": {
"core": ">=0.1.5-rc.1",
"plugins": [{ "name": "dsh-mobile", "required": true, "provides": "..." }],
"programs": [{ "name": "SakuraFrp 启动器 / frpc", "required": true, "platform": "Windows" }],
"services": [{ "name": "dsh-mobile-lan-watchdog.service", "required": false }],
"platform": ["Linux", "WSL2"], "node": ">=20"
}

3. 安装

3.1 一键安装(推荐)

git clone https://github.com/ankhishtar2-lang/dsh-sakurafrp.git
cd dsh-sakurafrp
bash scripts/install.sh # 拷贝到 profile + 注册 bundles + 静态自检
systemctl --user restart dsh-web-profiled.service # 生效(由你手动执行)

scripts/install.sh 只做三件事:把包拷进 $DSH_HOME/profiles/web/node_modules/、把 dsh-sakurafrp 追加进 profile package.json 的 dsh.profile.bundles、做静态自检(host 是否有 apply 导出是硬红线:缺了会让整棵插件树 boot 失败)。它也不会替你重启。

3.2 手动安装

cp -r dsh-sakurafrp "$DSH_HOME/profiles/web/node_modules/"
再把 "dsh-sakurafrp" 加进 $DSH_HOME/profiles/web/package.json 的 dsh.profile.bundles
dsh --profile web --dump-config >/dev/null && echo 配置可解析
systemctl --user restart dsh-web-profiled.service

3.3 前置:配置 dsh-mobile 的移动网关

在 $DSH_HOME/profiles/web/cordis.patch.yml 里加一段(值都要换成你自己的):

- id: mobile-access
config:
initiallyEnabled: true
maxDevices: 1 # 只信任一台设备就写 1 pairingTtlMs: 300000 # 配对窗口 5 分钟 listenHost: 127.0.0.1 listenPort: 33782 # 必须等于 SakuraFrp 隧道的远程端口 publicAuthorities:
- node.example.com:33782 # 手机访问时用的 Host,必须与隧道入口一致
- yd.node.example.com:33782 # SakuraFrp 运营商前缀节点(可选)
allowedCidrs: ['127.0.0.0/8', '::1/128'] # 隧道过来的源地址恒为回环
upstreamOrigin: http://127.0.0.1:3080
tls:
mode: provided
certFile: !!js dshHomePath('mobile-access/tls/server.crt')
keyFile: !!js dshHomePath('mobile-access/tls/server.key')
pairingCaFile: !!js dshHomePath('mobile-access/tls/ca.crt')
instanceId: '' # 必须与 CA 指纹完全一致

⚠️ 两个会让你起不来 dsh 的坑(作者踩过)
1. pairingCaFile 配了却漏了 instanceId:插件会拿 sha256(stateFile 路径) 当 instanceId,永远对不上 CA 指纹 → start() 抛错 → loader fail-fast → 整个 dsh web 起不来。
2. maxDevices 在「配对准入」时只数活跃设备,但在启动加载时数全部记录(含已撤销)。
撤销过设备后忘记清理、又把 maxDevices 改小,重启即崩。本仓库的 scripts/dsh-mobile-security-audit.sh 会自动清理已撤销记录。

安装方式补充:从 npm 安装(可选)

本包的 package.json 已按 npm 发布要求准备好(去掉 private、用 files 白名单控制内容)。
发布到 npm 后即可用 dsh 自己的命令安装(dsh plugin add 本质就是 pnpm add):

dsh plugin --profile web add dsh-sakurafrp

自己发布(需要你自己的 npm 账号;scripts/publish.sh 不接触也不保存任何 token):

npm login
bash scripts/publish.sh --dry # 自检 + 列出将要发布的文件,不发布 bash scripts/publish.sh # 真正发布(改过代码要先升 version,同版本号不可覆盖)

发布后请同步更新 README 与上游收录表的描述,保持「描述属实」这一条成立。

4. 配置(环境变量) If you don't want to modify the profile, all behavior can be overridden with environment variables (set them in the systemd unit or startup script):

| Variable | Default value | Description |
| DSH_SAKURA_ORIGIN | https://node.example.com:33782 (placeholder) | Required: your own public entry point. If the placeholder is not changed, both probing and pairing will fail |
| DSH_SAKURA_AUTHORITIES | empty | Additional public authorities to probe (comma-separated); the primary entry point is automatically taken from origin; SakuraFrp's yd./dx./lt. prefix nodes go here |
| DSH_SAKURA_SELFHEAL_MS | 15000 | Gateway self-healing polling interval |
| DSH_SAKURA_PROBE_MS | 60000 | Public node probing interval |
| DSH_SAKURA_LOG | $HOME/dsh/memory/dsh-sakurafrp.log | Event log (automatically created with 0600) |
| DSH_SAKURA_WATCHDOG_UNIT | dsh-mobile-lan-watchdog.service | External watchdog service unit name |
| DSH_SAKURA_SUPPRESS_FILE | $DSH_HOME/mobile-access/.gateway-user-disabled | Path of the suppression marker for "user has disabled mobile access"; when present, both self-healing and watchdog step aside |
| DSH_SAKURA_ADMIN_TOKEN | not set | Once set, the identification header for mutating routes must be this value (replace the public 1 with a real credential) |
| DSH_SAKURA_ALLOW_REMOTE_ADMIN | not set | When set to 1, disables the "desktop-only" gate (see section 6, not recommended) |

📌 Differences from the author's actual running version: The author's local copy sets the default value of DSH_SAKURA_ORIGIN to their own tunnel entry point
(to save configuring an environment variable). To avoid exposing a personal tunnel address, this repository changes the default value to the placeholder
https://node.example.com:33782, and by default no longer probes yd./dx./lt. prefix nodes.
Therefore, after installing from this repository, you must explicitly set DSH_SAKURA_ORIGIN (and DSH_SAKURA_AUTHORITIES if necessary).

5. HTTP routes

All are registered on dsh web (default 3080), and only accept loopback origins (anything non-loopback is rejected with 403):

| Method | Path | Desktop-only | Description |
| GET | /dsh-sakurafrp/status | No (redacted for mobile) | Aggregated status: gateway (including suppressed) / probing / devices / watchdog / self-healing counters |
| POST | /dsh-sakurafrp/control | ✅ | {running: bool} toggles mobile access; disabling writes the suppression marker, enabling clears it |
| POST | /dsh-sakurafrp/pair | ✅ | Requests a pairing window, returns pairUrl + inline qrDataUrl |
| GET | /dsh-sakurafrp/qr.svg | ✅ | The most recent QR code SVG (for debugging; the frontend now uses an inline data URL) |
| POST | /dsh-sakurafrp/revoke | ✅ | {deviceId} revokes a device |
| POST | /dsh-sakurafrp/devices/reset | ✅ | Clears all paired devices (sends confirm: true to dsh-mobile) |
| POST | /dsh-sakurafrp/selfheal | ✅ | Immediately performs one "ensure the gateway is running"; skipped if the user has disabled it |
| POST | /dsh-sakurafrp/probe | ✅ | Immediately probes all public nodes |
| POST | /dsh-sakurafrp/watchdog | ✅ | {active: bool} starts/stops the external watchdog service |

6. Security notes (please be sure to read)

6.1 Why there is a "desktop-only" gate

dsh-mobile's mobile gateway is a reverse proxy with a privileged upstream cookie: it forwards everything except /mobile-access/
to dsh web (3080), attaching the auth cookie it obtained by exchanging the DSH in-process launch token.
The consequence is: any paired device can reach all plugin routes registered on 3080, and the source address appears to be 127.0.0.1 in every case.

During a security review, the author actually tested this (using a real paired device from the public internet):

| Request | Before hardening | After hardening |
| POST /dsh-sakurafrp/pair | 200 (the phone could mint its own pairing code and then pull more devices in) | 403 desktop_only |
| POST /dsh-sakurafrp/watchdog {"active":false} | 200 (watchdog service stopped → self-healing disabled) | 403 desktop_only |
| POST /dsh-whale-tools/restart | 200 (dsh was actually restarted) | 403 desktop_only |

How the gate works (three layers, all must pass):

1. The source address must be loopback;
2. If Origin / Referer are present, they must be loopback (127.0.0.1 / ::1 / localhost).
When the gateway forwards, it rebuilds the request headers using a whitelist (only allowing
accept* / content-* / if-* / range / user-agent / origin / sec-fetch-site) — note that origin is in the whitelist, so when the phone accesses through the tunnel, the Origin the server can see is the tunnel domain, not loopback; a malicious web page would instead show the attacker's domain. Both are rejected. These two headers are filled in by the browser itself and cannot be changed by page scripts;
3. The request header x-dsh-sakurafrp-desktop: 1. When DSH_SAKURA_ADMIN_TOKEN is set,
this must be the value of that token (the real credential).

What it is and what it is not (please understand this accurately): The header in item 3 is a discriminator, not authentication — its value is publicly written in this README and the source code. The real boundary is: 3080 only binds to 127.0.0.1 + the gateway strips custom headers + a process that can send requests on the local machine already has equivalent user privileges (it can directly call the loopback management interface). So this gate blocks browser cross-site requests and devices coming through the public tunnel, but it does not sandbox local processes.
- 逃生舱:DSH_SAKURA_ALLOW_REMOTE_ADMIN=1 会让手机端也能管理(等于把上面三道全关掉,不建议)。
- 本插件不接触任何密钥:SakuraFrp 访问密钥始终只在 Windows 启动器手里;前端只处理一次性、短时有效的配对 token。
- 事件日志以 0600 创建,内容不含密钥与 token。

6.2 安全边界在哪

真正的安全边界是「设备配对」本身:配对成功后,那台设备就拥有完整的 DSH 会话(能驱动 agent、读写会话)——这是移动访问的功能本意。本插件收紧的是控制面(铸造配对码、开关网关、撤销设备、停守护、重启 dsh),不是会话面。
手机丢失/借人 ≈ 把 DSH 交出去;要收回就在电脑端面板撤销该设备。

7. 仓库脚本

| 脚本 | 用途 |
| scripts/install.sh | 幂等安装(拷贝 + 注册 bundles + 静态自检) |
| scripts/uninstall.sh | 卸载(移除 bundles + 删目录) |
| scripts/dsh-mobile-lan-watchdog.sh | 移动网关守护:发现 running:false 就拉起(systemd user 服务用) |
| scripts/dsh-mobile-security-audit.sh | 可复跑的审查脚本:匿名面 / 文件权限 / 「已配对设备越权」实测。⚠️ 它并不是完全非破坏性的:为了实测越权,它会真的在本机配对一台临时设备,因此会改写 ~/.dsh/mobile-access/devices.json(0600)。脚本结束时会清理该记录,但中途被打断会留下一条有效设备记录——跑完请用面板确认设备列表,或直接跑 devices/reset |
| scripts/legacy/dsh-mobile-pair.sh | 早期命令行配对脚本,已被插件面板取代,留作备用 |

审计脚本用法:

bash scripts/dsh-mobile-security-audit.sh [公网origin] 关键项全过 → 退出码 0;发现越权/暴露 → 1

8. 已验证 / 已知限制

已在作者本机验证

- 4 个公网节点探测全部 200 {"ok":true},延迟 161–235 ms(真实隧道,自签证书校验关闭);
- 真实配对 → 带会话拉取手机端首页 200;手机端所有控制面请求 403;
- host 半桩测试 37 项 + 浏览器半 bundle 复核;dsh --profile web --dump-config 退出码 0;
- 网关被静默关闭后 15 秒内自愈(多次实测)。

已知限制

- 只做「管理壳」,不提供隧道:隧道断了要去看 SakuraFrp 启动器/面板;
- 依赖 dsh-mobile 的内部管理接口,上游改路径就会失效(接口非公开契约);
- 公网探测会周期性向公网节点发 HTTPS 请求(每 60 秒 4 条,可 DSH_SAKURA_PROBE_MS 调大或关掉插件);
- 面板为原生 DOM + 内联样式,深色/浅色主题都做了变量兜底,但主题差异大的皮肤下观感可能一般;
- 手机端只能读状态,这是设计而非缺陷。

9. 卸载

bash scripts/uninstall.sh
systemctl --user restart dsh-web-profiled.service

卸载本插件不会影响:SakuraFrp 隧道、mobile-access 配置与自签证书、设备状态文件、外部守护服务。这些要单独处理(见第 3.3 节的配置段)。

10. 目录结构

dsh-sakurafrp/
├── package.json # dsh.bundle / dsh.client / peerDependencies / dshDependencies
├── cordis.patch.yml # loader 条目:id=sakurafrp, name=dsh-sakurafrp ├── lib/ │ ├── index.js # host 半:9 条路由 + 网关自愈(尊重用户关闭)+ 公网探测 + 桌面闸门 │ └── client.js # 浏览器半:头部手机按钮 + 管理面板 + 每秒倒计时 ├── scripts/ # install.sh / uninstall.sh / publish.sh / 守护 / 安全审计 / 早期配对 ├── LICENSE # MIT └── README.md

11. 许可

MIT © 2026 ankhishtar2-lang —— 见 LICENSE。
再次提醒:vibe coding 产物,未经人工逐行审计,按「原样」提供,风险自负。
预览分享卡片长什么样 ↓ArimaKana-Akane/dsh-sakurafrp
分享 · DeepSeek Harness Hub
ArimaKana-Akane/dsh-sakurafrp

在会话头部管理手机隧道,扫码配对并自愈网关

这是你的仓库?认领条目

回到顶部