Skip to content

Releases: Zoragyx/dsh-phone-pair

DSH 手机版 · 配对版 1.0.3(支持局域网 http 配对)

Choose a tag to compare

@Zoragyx Zoragyx released this 13 Oct 11:06

DSH 手机版 · 配对版 1.0.3 —— 局域网 http 配对(推翻 1.0.2 的一个判断)

1.0.2 的说明里写着「局域网 http 仍然有意不支持」。这一版把它改了,因为那个判断站不住:

  • 上游 @linxin666/dsh-remote-web-ui 本来就支持局域网 http。它签发的设备 Cookie 只在走 TLS 时才加 Secure,源码注释写得很直白:LAN pairing runs on plain HTTP, where a Secure cookie is simply dropped by the browser and the phone would silently lose its session. —— 也就是说"电脑走 http、手机走 https"这套组合从头到尾只有我们这一侧在挡。
  • 后果是真实用户整条路走不通:一位测试员的电脑绑在 0.0.0.0,面板给的是 http://100.68.26.79:19387/pair-accept?pair=…(Tailscale 地址)。1.0.2 只会回一句「需要完整的配对链接」,他无论怎么复制都配不上。
  • 我们当时的顾虑(打开 cleartext 明文流量会放宽信任边界)是对的,但解法不该是"要求所有人改用公网 https",而是只放行内网地址。这一版就是这么做的。

修了什么

现象 1.0.2 1.0.3
面板切到「局域网地址」,粘 http://192.168.1.5:19387/pair-accept?pair=… 拒绝(只认 https://) 接受,直接配对
Tailscale 用户(http://100.68.x.x:19387/…) 拒绝,全流程走不通 接受(100.64.0.0/10 是 CGNAT 私网段)
http:// + 公网域名 拒绝 仍然拒绝,提示改用 https / 面板的「公网地址」

放行范围写死在 PairLinks.isPrivateHost():10. / 172.16-31. / 192.168. / 169.254. / 100.64-127. / 127.、*.local / .lan / .home / .internal / .ts.net、以及单段主机名(mDNS/NetBIOS,如 desktop、my-pc.local)。

配套改动

  • Cookie 的 Secure 标志按 scheme 决定:https 加 ; secure,http 不加。不这样改,WebView 会直接丢弃这条 Cookie,表现为「配对成功、一刷新就掉线」。
  • 内置资源拦截(85 个客户端 bundle / 28.2 MB)从"仅 https 同源"放宽为"http 或 https,但 host 必须等于已配对主机"。
  • AndroidManifest.xml 打开 usesCleartextTraffic(Android 默认禁止明文),但真正的门在代码里:只有内网地址的 http 链接能通过解析,WebView 的导航仍被 shouldOverrideUrlLoading 限制在已配对主机上,公网 http 站点进不来。
  • 配对链接的 intent-filter 增加 http scheme:点开局域网链接也能直接进 App。
  • 配对浮层引导文案写清"两种链接都能用",关于 页版本号改 1.0.3。

顺手补的文档

  • 新增 tester-troubleshooting.md(测试员版排查步骤,可直接转给测试员):先看版本 → 再看面板顶部状态 → 同一网络直接走局域网 → 想走公网才去修中继红字 → 浏览器"无法保存确认状态"怎么办 → 还不行要提供哪 5 项信息。
  • 工程树与发布树的 README「常见问题」表、插件 README「排错」表同步改成 1.0.3 的说法(局域网 http 从"不支持"改为"支持,仅限内网地址")。

怎么升级

  1. 下载本页的 DSH-Phone-Pair-1.0.3.apk,直接覆盖安装(与 1.0.0 / 1.0.1 / 1.0.2 同一把签名 key,不必先卸载,数据保留);
  2. 电脑上打开「远程访问」面板 → 选网络(同一网络用「局域网地址」,在外网用「公网地址」)→ 点『复制链接』 → 发到手机 → 在 App 的配对页粘贴;
  3. 在 App「设置 / 帮助 → 关于」里看到 DSH 手机版 · 配对版 1.0.3 就装对了。

走局域网地址的前提是手机和电脑在同一个网络(同一个 Wi-Fi,或都在同一个 Tailscale 网络里)。公网地址则要求电脑侧的中继是正常的(面板顶部显示「固定域名:正常」)。

校验

项 值
文件 DSH-Phone-Pair-1.0.3.apk
大小 12,373,348 字节(约 11.8 MiB)
SHA256 60875A94160F3F736F5CAB1E829964D29BA0DF099FA221D3282576B2604D2CEB
包名 / 版本 com.dsh.phone.pair / versionCode 4、versionName 1.0.3
最低系统 Android 8.0(API 26),targetSdk 34
签名 CN=DSH Phone,SHA-256 b9204950d591bb3329ec137180673a98e2899e32fff91f23889585cc78ec1a0f(可覆盖升级)
内置资源 85 个文件 / 28.2 MB(离线也能画界面)

单元测试(JVM,无 JUnit 依赖):PairLinksTest 74 通过 / 0 失败(新增 12 条局域网/私网地址用例:192.168.、10.、172.20.、100.64.、100.68.26.79(测试员那条)、*.local、单段主机名、无 scheme 补 http、公网 http 仍拒绝、10.evil.com 这类伪前缀不认),AssetIndexTest 33 通过 / 0 失败。

DSH 手机版 · 配对版 1.0.2(配对链接更好懂)

Choose a tag to compare

@Zoragyx Zoragyx released this 13 Oct 10:49

DSH 手机版 · 配对版 1.0.2 —— 不让「复制粘贴」再把人挡在门外

这一版是照着真实测试反馈改的(感谢 B 站网友 RikiYuko 的两条报障)。功能没变,改的是"人话"。

修了什么

1. App 里粘贴过去,总说「输入完整的链接」

旧版的链接解析只认一种形状:https://<host>/pair-accept?pair=<码>。而面板上能复制到的其实有三种"看着像链接、其实不合格"的东西:

你复制的 实际是什么 旧版反应
屏幕上看得见的那截文字 面板是 CSS 省略号截断显示的(…/pair-accept?pair=fcb…),你选中的是残链接 拒绝
点了『复制令牌』 那是给 Docker / 反向代理环境用的裸令牌,不是链接 拒绝
面板回退时的 http://192.168… 局域网地址(http),手机端只走 https 拒绝

三种情况旧版都只回一句「需要完整的配对链接」,谁也猜不出问题在哪。1.0.2 起:

  • 容错:粘贴时自动忽略零宽字符、不换行空格、换行(微信/QQ 转发经常塞这些),也接受不带 https:// 的裸链接(自动补上);
  • 会说话:分别提示
    • 「链接被截断了(结尾是省略号 …)……请改点『复制链接』按钮」
    • 「这是『配对令牌』,不是配对链接」
    • 「这是局域网地址(http://…),手机端只使用 https 地址」
    • 「链接里缺少 ?pair= 参数」/「配对码不足 8 位」
  • 配对浮层的引导也换成:「点『复制链接』(不是『复制令牌』)」;面板上如果写着「固定域名同步失败」或只剩局域网地址,会先让你在电脑侧修好。

局域网 http 仍然有意不支持:要支持它得在清单里打开 cleartext 明文流量、并放宽同源判断,安全代价不划算。所以我们选择"准确告诉你怎么做对",而不是"降低安全门槛"。

2. 手机浏览器点「继续」提示「暂时无法保存确认状态,请重试」

这句不是本 App 的文案,是 DSH 自己的「预览版说明」弹窗(welcomeError):它要把"已确认"写回电脑,而多数情况下是浏览器没带上配对 Cookie —— 微信/QQ 内置浏览器、无痕模式、手输网址或另存书签再打开,都会这样。

正确姿势(已写进 README 的「常见问题」):

  1. 从聊天窗口里直接点开配对链接(别手输、别存书签后再打开);
  2. 用系统 Chrome / Edge,关掉无痕,别用"阻止第三方 Cookie";
  3. 或者直接用配对版 App:设备凭据存在 App 本地,不走浏览器 Cookie,最省事。

顺手补的文档

  • 两个 README(工程树 + 发布树)新增「常见问题(都来自真实测试反馈)」表:链接被截断 / 复制成了令牌 / 局域网地址 / 面板红字「固定域名同步失败」(本机 HTTPS_PROXY 指向没启动的代理时,插件的 fetch 会直接失败)/ 浏览器无法保存确认状态。
  • 插件 README 的「排错」表补上同样五条。
  • 把配对码到底在哪写清楚了:面板入口 = 设置按钮旁边的手机图标,或「设置 → Web 插件 → 远程访问」(单独装插件时在设置里的插件行);并且强调点『复制链接』,不是『复制令牌』。

怎么升级

  1. 下载本页的 DSH-Phone-Pair-1.0.2.apk,直接覆盖安装(与 1.0.0 / 1.0.1 同一把签名 key,不必先卸载,数据保留);
  2. 电脑上打开「远程访问」面板 → 刷新二维码 → 点『复制链接』 → 发到手机 → 在 App 的配对页粘贴;
  3. 在 App「设置 / 帮助 → 关于」里看到 DSH 手机版 · 配对版 1.0.2 就装对了。

校验

项 值
文件 DSH-Phone-Pair-1.0.2.apk
大小 12,373,348 字节(约 11.8 MiB)
SHA256 3614516B4F1CEECC50B081E4CDA5440707689B4FA737A51E8461500A6BDD80B0
包名 / 版本 com.dsh.phone.pair / versionCode 3、versionName 1.0.2
最低系统 Android 8.0(API 26),targetSdk 34
签名 CN=DSH Phone,SHA-256 b9204950d591bb3329ec137180673a98e2899e32fff91f23889585cc78ec1a0f(可覆盖升级)
内置资源 85 个文件 / 28.2 MB(离线也能画界面)

单元测试(JVM,无 JUnit 依赖):PairLinksTest 62 通过 / 0 失败(含省略号截断、零宽字符、无 scheme 链接、局域网 http、五类提示文案),AssetIndexTest 33 通过 / 0 失败。

DSH 手机版 · 配对版 1.0.1(修复首次配对失败)

Choose a tag to compare

@Zoragyx Zoragyx released this 12 Oct 10:32

DSH 手机版 · 配对版 1.0.1 —— 修复「第一次配对必然失败」

这个版本只修一个 bug,但它是致命的。

现象

全新安装的 App 永远完不成第一次配对,一直提示:

配对失败:配对链接可能已过期,请在电脑上重新生成

即使配对链接完全有效——同一条链接在手机浏览器里能正常配对(这也是最容易误判的地方:
看起来像链接或中继的问题,其实是 App 自己的问题)。而且失败是"秒失败":刚点开始配对就报错。

原因

App 用「已经记住的那台电脑的地址」去读服务器的配对 cookie,而"记住这台电脑"这一步写在
配对成功之后:

没记住电脑 → 不去读 cookie → 读不到新 cookie → 判定没配对成功 → 不记住电脑 → …

死循环,所以第一次配对永远出不来。这个判断又是本地同步做的,于是表现为"刚粘上就失败"。

浏览器不受影响(没有这段逻辑),因此会出现"浏览器好使、App 不好使"。

修复

  • java/com/dsh/phone/MainActivity.java 的 readPairCookie():在还没记住电脑时,回退使用
    你刚粘贴的那条链接里的主机
    去读 cookie(并加了注释说明这个死锁,防止以后再犯)。
  • 版本号:versionCode 1 → 2、versionName 1.0 → 1.0.1。
    装好后在 App 里「设置 / 帮助 → 关于」能看到 DSH 手机版 · 配对版 1.0.1,可用来确认装对了。

升级与配对(三步)

  1. 下载本页的 DSH-Phone-Pair-1.0.1.apk 覆盖安装(与 1.0.0 同一把签名 key,不用先卸载,数据保留);
  2. 电脑上打开 DSH →「远程访问」面板 → 刷新二维码 → 复制链接;
  3. 手机上把链接粘进 App →「开始配对」。

小提示:配对链接只有最新签发的那一条有效——点「刷新二维码」会让之前复制出去的链接立刻失效
(服务端的配对 token 有效期为 10 分钟)。所以复制之后请尽快粘贴,中途不要再点刷新。

校验

项 值
文件 DSH-Phone-Pair-1.0.1.apk
大小 12,369,252 字节
SHA256 5690470F3668A2BDD85681CBFF12312BF000AFAEE55D7E82325AF04D76717B76
包名 / 版本 com.dsh.phone.pair / versionCode 2、versionName 1.0.1
最低系统 Android 8.0(API 26)
签名 CN=DSH Phone, OU=Personal, O=DSH Phone(与 1.0.0 同一把 key)
权限 仅 INTERNET、ACCESS_NETWORK_STATE

DSH 手机版 · 配对版 1.0

Choose a tag to compare

@Zoragyx Zoragyx released this 10 Oct 13:18

DSH 手机版 · 配对版 1.0

安卓手机上的 DSH 客户端。通用配对版:安装包不含任何凭据、不含任何电脑地址,可以随便转发;每个人装好后配对自己电脑即可。

下载

文件 大小 SHA256
DSH-Phone-Pair-1.0.apk 12,373,348 字节 863F7B3175EE089FAE9FD358F1DA43E7181DF3311E727C922A24E58C8C3FAB76
  • 包名 com.dsh.phone.pair · 应用名「DSH 手机版 · 配对版」 · versionName 1.0(versionCode 1)
  • minSdk 26(Android 8.0)· targetSdk 34 · 权限只有 INTERNET 与 ACCESS_NETWORK_STATE
  • 签名证书 SHA-256 b9204950d591bb3329ec137180673a98e2899e32fff91f23889585cc78ec1a0f(自签名)
  • 约 28 MB 前端(85 个内容哈希资源)已打进包里,首次打开不必等下载界面

装好之后怎么用

  1. 电脑侧(每台一次):装 DSH → 装插件 @linxin666/dsh-remote-web-ui(自带 cloudflared,不需要 Cloudflare 账号或域名)→ 打开它的「自动隧道」→ 复制配对链接 https://<id>.dsh-market.com/pair-accept?pair=<code>。
  2. 手机侧:装 APK → 设置本机密码(PBKDF2-HMAC-SHA256,10 万次迭代,只存手机)→ 点开或粘贴配对链接 → 进入你自己的 DSH 界面。
  3. 之后每次打开只要输密码。设备凭据有效期一年,电脑重启、换 IP、换网络都不用重新配对。

本仓库的 plugin/dsh-phone-pair-kit 是可选配套插件,装上会自动把上面第 1 步的开关打开:

pnpm add github:Zoragyx/dsh-phone-pair#path:plugin/dsh-phone-pair-kit
# ↑ 这条需要本机有 git;没装 git 就在仓库页面 Code → Download ZIP,
#   解压后 pnpm add <解压目录>\plugin\dsh-phone-pair-kit

这一版做了什么

  • 通用化:构建期不再把 BASE_URL/BASE_HOST/DEVICE_ID 编译进包,改成运行期从配对链接学习站点,凭据存手机本地。
  • 修掉一个首次配对必现的 bug:配对成功后是 303 跳转 /pair-accept → /pair-app?grant=…,旧逻辑在未配对时把跳转交给系统浏览器,导致 cookie 写不进、界面停在「配对失败」。现在按配对链接的 host 放行跳转。
  • 同源闸门:只有目标站点自己的路径才从包内直接提供资源。
  • 密码锁屏 + 退到后台再回来重新验证;「复位本机」一键清掉密码与配对。

验证(本轮实测)

检查 结果
单元测试 PairLinksTest passed=50、AssetIndexTest passed=33
真数据命中 外壳 85 个 URL → hits: 85 ; misses: 0
包内资源逐字节比对 85/85 verified byte-identical, 29,546,654 bytes (28.2 MB)
凭据审计 verdict : OK - no build-time credential or cookie inside the package
全新配对链路 公网兑换 200 → /pair-app?grant=… → 新凭据解锁 200 → 撤销后设备数不变
打包 zipalign 通过 · apksigner verify 通过 · aapt2 badging 包名/版本/权限正确

注意

  • 电脑关机就不能用:App 只是手机端界面,DSH 与 Agent 都跑在电脑上。关机、睡眠、退出 DSH 都会断开,唤醒后 1~2 分钟自动恢复,不需要重新配对。
  • 配对成功的设备 = 完全控制凭据(聊天、会话、设置、凭据、Agent 预设、产出物)。只在自己的手机上配对,配对链接默认 10 分钟过期。
  • 电脑上的 DSH 始终保持 127.0.0.1 回环绑定,公网可达性由 cloudflared 出站隧道提供;不想要就在面板里撤销设备。
  • 中继(dsh-market.com)偶发 530/截断只影响外壳那几十 KB,界面资源都在包内。

灵感来源与致谢

  • 这个 App 的灵感与配对思路来自开源插件 @linxin666/dsh-remote-web-ui(作者 linxin666,源码仓库 https://github.com/zhu1090093659/dsh-web,Apache-2.0):/pair-accept?pair=<code> 一次性令牌、/pair-app 手机版界面壳、可撤销的设备会话、固定域名中继 <id>.dsh-market.com、设置页的「远程访问」面板与二维码都出自它。感谢原作者 linxin666。
  • 在这个思路上,本项目独立完成了手机端:安卓 WebView 外壳、本机密码锁屏、离线优先缓存、把约 28 MB 前端资源打进包内、从配对链接运行期学习主机,以及构建/审计/验证/发布的全套脚本;另附配套插件 plugin/dsh-phone-pair-kit。本仓库不包含上游插件的源码。
  • 插件骨架的写法参考了 dsh-orb(作者 mini-yifan,MIT),谨致谢意。
  • APK 内置的前端资源来自 DSH 自己的 Web 界面(构建时从使用者电脑抓取),版权归 DSH 作者;如认为不宜随 APK 分发,告知后会立刻删除该资产或改为不含内置前端的构建。
  • 本项目是社区第三方作品,与 DeepSeek / DSH 官方及上述作者没有隶属关系,也未声称获得其背书;**若说明或做法有任何不妥,请提 issue,我们会立即修改或下架。**完整清单见仓库根目录 NOTICE.md。

许可

本项目自己的代码:MIT,见 LICENSE。第三方组件(@linxin666/dsh-remote-web-ui Apache-2.0、dsh-orb MIT、cloudflared Apache-2.0)各自遵循自己的许可,详见 NOTICE.md。