@mrrisega/dsh-remote 0.6.0-beta.12 → 0.6.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/README.md +3 -43
  2. package/clients/dsh-remote/dsh-bridge.mjs +5 -335
  3. package/package.json +2 -2
  4. package/packages/dsh-remote-web/lib/client.js +183 -607
  5. package/packages/dsh-remote-web/lib/index.js +10 -139
  6. package/packages/dsh-remote-web/test/access-key-sessions.test.mjs +11 -81
  7. package/packages/dsh-remote-web/test/account-switch.test.mjs +1 -1
  8. package/packages/dsh-remote-web/test/feedback-proxy.test.mjs +1 -2
  9. package/packages/dsh-remote-web/test/remote-access-ui.test.mjs +3 -175
  10. package/packages/dsh-remote-web/test/settings-entry.test.mjs +5 -56
  11. package/packages/dsh-remote-web/test/uninstall-runtime.test.mjs +2 -2
  12. package/clients/dsh-remote/e2ee-client.mjs +0 -728
  13. package/clients/dsh-remote/e2ee-shim-script.js +0 -737
  14. package/clients/dsh-remote/e2ee-shim.mjs +0 -163
  15. package/clients/dsh-remote/mobile-adapter.mjs +0 -595
  16. package/clients/dsh-remote/test/bridge-html-inject.test.mjs +0 -110
  17. package/clients/dsh-remote/test/e2ee-bridge.test.mjs +0 -630
  18. package/clients/dsh-remote/test/e2ee-client.test.mjs +0 -378
  19. package/clients/dsh-remote/test/e2ee-shim.test.mjs +0 -507
  20. package/clients/dsh-remote/test/e2ee-wecrypto-parity.test.mjs +0 -200
  21. package/clients/dsh-remote/test/lib-e2ee-shim.mjs +0 -59
  22. package/clients/dsh-remote/test/lib-native-e2ee.mjs +0 -92
  23. package/clients/dsh-remote/test/mobile-adapter.test.mjs +0 -124
  24. package/packages/dsh-remote-web/test/e2ee-state.test.mjs +0 -141
  25. package/packages/dsh-remote-web/test/feedback-account-mine.test.mjs +0 -70
  26. package/packages/dsh-remote-web/test/password-reset.test.mjs +0 -430
@@ -1,6 +1,6 @@
1
1
  // dsh-remote-web 浏览器半回归(2026-09 前名 dsh-remote-ui):面板入口迁移进「设置」页 settings.section 官方扩展点。
2
- // 覆盖:栏目注册(id/order/label)、侧边栏入口与浮动面板移除(不再向官方侧栏注入任何按钮/点击机器)、
3
- // 账号区无「切换账号」、「关于 dsh-remote」说明卡片、退出登录/切换连接账号清理反馈线程凭据、首次安装红点引导。
2
+ // 覆盖:栏目注册(id/order/label)、侧边栏入口与浮动面板移除、账号区无「切换账号」、
3
+ // 「关于 dsh-remote」说明卡片、退出登录/切换连接账号清理反馈线程凭据、首次安装红点引导。
4
4
  import assert from "node:assert/strict";
5
5
  import { readFileSync } from "node:fs";
6
6
  import test from "node:test";
@@ -87,7 +87,6 @@ function loadPlugin(opts = {}) {
87
87
  });
88
88
 
89
89
  const allCreated = [];
90
- const intervals = [];
91
90
  const doc = {
92
91
  createElement(tag) { const el = makeEl(tag); allCreated.push(el); return el; },
93
92
  head: makeEl("head"),
@@ -96,10 +95,7 @@ function loadPlugin(opts = {}) {
96
95
  const cls = sel.charAt(0) === "." ? sel.slice(1) : "";
97
96
  return allCreated.find((el) => el.className === cls) || null;
98
97
  },
99
- querySelectorAll(sel) {
100
- if (sel === "button") return opts.navCells || [];
101
- return [];
102
- },
98
+ querySelectorAll(sel) { return sel === "button" ? (opts.navCells || []) : []; },
103
99
  };
104
100
 
105
101
  let lastObserver = null;
@@ -133,7 +129,7 @@ function loadPlugin(opts = {}) {
133
129
  return response(200, { body: { ok: true } });
134
130
  },
135
131
  navigator: { clipboard: { writeText: async () => {} } },
136
- setInterval(cb, ms) { intervals.push({ cb, ms }); return intervals.length; },
132
+ setInterval() { return 1; },
137
133
  clearInterval() {},
138
134
  setTimeout() { return 1; },
139
135
  Set,
@@ -156,7 +152,6 @@ function loadPlugin(opts = {}) {
156
152
 
157
153
  return {
158
154
  registered, metas, injects, requests, removed, states, localStorage,
159
- intervals,
160
155
  lastObserver: () => lastObserver,
161
156
  renderSection() { hook = 0; return registered.get("dsh-remote")({ close() {} }); },
162
157
  };
@@ -208,7 +203,7 @@ test("登录态账号区:无「切换账号」,有「退出登录」,头
208
203
  "📱 远程访问:用手机或另一台电脑的浏览器,随时随地使用同一份 dsh web——人在哪都能用(免公网 IP、免内网穿透);官方托管中继,4G/5G 即用,也可自建服务。",
209
204
  "🛠 电脑端一键安装:bridge 与「远程访问」面板一次到位——云端/自建切换、账号登录、bridge 启停、一次性扫码访问、已授权设备管理、意见反馈都在这里。",
210
205
  "🔒 安全与通道:HTTP / WebSocket 全量透传,一次性访问密钥认证,面板实时显示设备与已授权设备列表;服务端可配置流量配额。",
211
- "🛡 端到端加密:手机↔电脑之间的消息内容用「你的账号密码派生密钥」端到端加密——密钥与密码不落服务端(仅存校验值),中继只可见路径/大小/时间(详见 README「安全与隐私」)。",
206
+ "🛡 端到端流量保护:可选对通道做端到端加密保护,传输全程不暴露本机公网 IP(详见项目 README「安全」说明)。",
212
207
  ];
213
208
  for (const p of points) {
214
209
  assert.ok(find(tree, (n) => n.children?.includes(p)), `说明卡片应含要点: ${p.slice(0, 12)}…`);
@@ -282,52 +277,6 @@ test("红点已看过(localStorage 有 key)时不注入,重启 DSH Web 不
282
277
  assert.equal(navCell.children.length, 0, "已看过时不应再注入红点");
283
278
  });
284
279
 
285
- test("红点只挂在设置页「远程访问」栏目导航(navCell):普通按钮即使文本含「远程访问」也不注入,不遮挡官方入口", () => {
286
- const navCells = [];
287
- const officialCell = makeEl("button");
288
- officialCell.className = "VOzbGW_navCell"; // shell hashed 类名(含 navCell 子串)=设置页栏目导航
289
- officialCell.textContent = "📱 远程访问";
290
- const plainBtn = makeEl("button");
291
- plainBtn.className = "some-other-btn"; // 非 navCell(官方侧栏/内容区按钮):即使含「远程访问」也不得注入
292
- plainBtn.textContent = "远程访问";
293
- const plugin = loadPlugin({ navCells });
294
-
295
- navCells.push(officialCell, plainBtn);
296
- plugin.lastObserver().cb([]);
297
-
298
- assert.equal(officialCell.children.length, 1, "官方设置页「远程访问」栏目按钮应注入红点");
299
- assert.equal(officialCell.children[0].className, "dru-reddot");
300
- assert.equal(plainBtn.children.length, 0, "非栏目导航按钮不得注入红点(不遮挡官方按钮)");
301
- });
302
-
303
- // ---------- 侧栏「远程访问」快捷入口(2026-09 恢复注入:与官方「设置」共存、不遮挡) ----------
304
- // 用户要求:左侧官方「设置」按钮旁保留「📱 远程访问」快捷按钮。实现要点(防 Bug A 复发):
305
- // - 独立 <button id=dru-nav-remote>(绝不 cloneNode → 不继承官方事件委托/点击热区),
306
- // 插在官方「设置」按钮之前;
307
- // - 候选限定官方导航(class 含 navCell 或位于导航容器)+ 短文本/aria 精确匹配;
308
- // - 命中排除自身(防递归)与“菜单/更多”语义节点;不点工作区会话行;
309
- // - openRemoteSettings:栏目已开直接点;未开先点官方「设置」再 ≤3s 轮询补点;
310
- // - 红点(.dru-reddot / .dru-nav-remote-dot)用同一 dsh-remote-seen-dot key,点击即收起。
311
-
312
- test("源码约束:侧栏注入「远程访问」按钮与官方「设置」共存;独立按钮非克隆;导航点击安全", () => {
313
- // 注入存在:入口 id / 挂载函数 / 打开函数 / 心跳保证
314
- assert.match(SOURCE, /dru-nav-remote/);
315
- assert.match(SOURCE, /navEnsureStart/);
316
- assert.match(SOURCE, /openRemoteSettings/);
317
- assert.match(SOURCE, /__dshRemoteNav/);
318
- assert.match(SOURCE, /data-dru-remote/);
319
- assert.match(SOURCE, /NAV_ENTRY_ID/);
320
- // 安全设计:绝不克隆官方按钮;候选限定 navCell/导航容器 + 短文本;排除自身;排除菜单语义
321
- assert.doesNotMatch(SOURCE, /cloneNode/);
322
- assert.match(SOURCE, /navCell/);
323
- assert.match(SOURCE, /NAV_TEXT_MAX/);
324
- assert.match(SOURCE, /el\.id === NAV_ENTRY_ID/);
325
- assert.match(SOURCE, /NAV_BAD_RE/);
326
- // 红点仍在(官方栏目 navCell + 快捷按钮首用同 key)
327
- assert.match(SOURCE, /dru-reddot/);
328
- assert.match(SOURCE, /dsh-remote-seen-dot/);
329
- });
330
-
331
280
  test("源码约束:无侧边栏入口/浮动面板/切换账号;命名统一为「远程访问」;新增访问密钥/设备路由", () => {
332
281
  // 只断言“代码形态”不存在(注释里允许出现说明文字)
333
282
  assert.doesNotMatch(SOURCE, /slots\.inject\("sidebar\.footer\.action"/);
@@ -77,7 +77,7 @@ async function plantInstallation(tempHome, opts = {}) {
77
77
  return { relayDir, profile };
78
78
  }
79
79
 
80
- test("彻底卸载:配置目录整目录清空(含账号/密钥/固化运行时),不误伤 profile 其它条目与家目录其它数据", { skip: process.platform !== "darwin" }, async () => {
80
+ test("彻底卸载:配置目录整目录清空(含账号/密钥/固化运行时),不误伤 profile 其它条目与家目录其它数据", async () => {
81
81
  const tempHome = await mkdtemp(path.join(os.tmpdir(), "dsh-ui-rt-"));
82
82
  const prevHome = process.env.HOME;
83
83
  process.env.HOME = tempHome;
@@ -220,7 +220,7 @@ test("DSH_RELAY_SKIP_SERVICE 开关:置位时即便存在自启动 plist 也
220
220
  }
221
221
  });
222
222
 
223
- test("自然跳过(无开关):HOME 有 plist 但服务未运行 → 删除 plist 但不发 launchctl bootout(PATH 假命令接管)", { skip: process.platform !== "darwin" }, async () => {
223
+ test("自然跳过(无开关):HOME 有 plist 但服务未运行 → 删除 plist 但不发 launchctl bootout(PATH 假命令接管)", async () => {
224
224
  const tempHome = await mkdtemp(path.join(os.tmpdir(), "dsh-ui-rt-natural-"));
225
225
  const prevHome = process.env.HOME;
226
226
  const prevPath = process.env.PATH;