@mrrisega/dsh-remote 0.6.0-beta.8 → 0.6.0
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.
- package/README.md +10 -3
- package/clients/dsh-remote/dsh-bridge.mjs +30 -0
- package/clients/dsh-remote/e2ee-client.mjs +17 -0
- package/clients/dsh-remote/e2ee-shim-script.js +43 -3
- package/clients/dsh-remote/e2ee-shim.mjs +5 -0
- package/clients/dsh-remote/mobile-adapter.mjs +56 -2
- package/clients/dsh-remote/test/e2ee-client.test.mjs +13 -0
- package/package.json +1 -1
- package/packages/dsh-remote-web/lib/client.js +410 -133
- package/packages/dsh-remote-web/lib/index.js +109 -8
- package/packages/dsh-remote-web/test/access-key-sessions.test.mjs +79 -9
- package/packages/dsh-remote-web/test/e2ee-state.test.mjs +1 -1
- package/packages/dsh-remote-web/test/feedback-proxy.test.mjs +2 -1
- package/packages/dsh-remote-web/test/password-reset.test.mjs +430 -0
- package/packages/dsh-remote-web/test/remote-access-ui.test.mjs +104 -7
- package/packages/dsh-remote-web/test/settings-entry.test.mjs +56 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// dsh-remote-web 浏览器半回归(2026-09 前名 dsh-remote-ui):面板入口迁移进「设置」页 settings.section 官方扩展点。
|
|
2
|
-
// 覆盖:栏目注册(id/order/label
|
|
3
|
-
//
|
|
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,6 +87,7 @@ function loadPlugin(opts = {}) {
|
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
const allCreated = [];
|
|
90
|
+
const intervals = [];
|
|
90
91
|
const doc = {
|
|
91
92
|
createElement(tag) { const el = makeEl(tag); allCreated.push(el); return el; },
|
|
92
93
|
head: makeEl("head"),
|
|
@@ -95,7 +96,10 @@ function loadPlugin(opts = {}) {
|
|
|
95
96
|
const cls = sel.charAt(0) === "." ? sel.slice(1) : "";
|
|
96
97
|
return allCreated.find((el) => el.className === cls) || null;
|
|
97
98
|
},
|
|
98
|
-
querySelectorAll(sel) {
|
|
99
|
+
querySelectorAll(sel) {
|
|
100
|
+
if (sel === "button") return opts.navCells || [];
|
|
101
|
+
return [];
|
|
102
|
+
},
|
|
99
103
|
};
|
|
100
104
|
|
|
101
105
|
let lastObserver = null;
|
|
@@ -129,7 +133,7 @@ function loadPlugin(opts = {}) {
|
|
|
129
133
|
return response(200, { body: { ok: true } });
|
|
130
134
|
},
|
|
131
135
|
navigator: { clipboard: { writeText: async () => {} } },
|
|
132
|
-
setInterval() { return
|
|
136
|
+
setInterval(cb, ms) { intervals.push({ cb, ms }); return intervals.length; },
|
|
133
137
|
clearInterval() {},
|
|
134
138
|
setTimeout() { return 1; },
|
|
135
139
|
Set,
|
|
@@ -152,6 +156,7 @@ function loadPlugin(opts = {}) {
|
|
|
152
156
|
|
|
153
157
|
return {
|
|
154
158
|
registered, metas, injects, requests, removed, states, localStorage,
|
|
159
|
+
intervals,
|
|
155
160
|
lastObserver: () => lastObserver,
|
|
156
161
|
renderSection() { hook = 0; return registered.get("dsh-remote")({ close() {} }); },
|
|
157
162
|
};
|
|
@@ -203,7 +208,7 @@ test("登录态账号区:无「切换账号」,有「退出登录」,头
|
|
|
203
208
|
"📱 远程访问:用手机或另一台电脑的浏览器,随时随地使用同一份 dsh web——人在哪都能用(免公网 IP、免内网穿透);官方托管中继,4G/5G 即用,也可自建服务。",
|
|
204
209
|
"🛠 电脑端一键安装:bridge 与「远程访问」面板一次到位——云端/自建切换、账号登录、bridge 启停、一次性扫码访问、已授权设备管理、意见反馈都在这里。",
|
|
205
210
|
"🔒 安全与通道:HTTP / WebSocket 全量透传,一次性访问密钥认证,面板实时显示设备与已授权设备列表;服务端可配置流量配额。",
|
|
206
|
-
"🛡
|
|
211
|
+
"🛡 端到端加密:手机↔电脑之间的消息内容用「你的账号密码派生密钥」端到端加密——密钥与密码不落服务端(仅存校验值),中继只可见路径/大小/时间(详见 README「安全与隐私」)。",
|
|
207
212
|
];
|
|
208
213
|
for (const p of points) {
|
|
209
214
|
assert.ok(find(tree, (n) => n.children?.includes(p)), `说明卡片应含要点: ${p.slice(0, 12)}…`);
|
|
@@ -277,6 +282,52 @@ test("红点已看过(localStorage 有 key)时不注入,重启 DSH Web 不
|
|
|
277
282
|
assert.equal(navCell.children.length, 0, "已看过时不应再注入红点");
|
|
278
283
|
});
|
|
279
284
|
|
|
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
|
+
|
|
280
331
|
test("源码约束:无侧边栏入口/浮动面板/切换账号;命名统一为「远程访问」;新增访问密钥/设备路由", () => {
|
|
281
332
|
// 只断言“代码形态”不存在(注释里允许出现说明文字)
|
|
282
333
|
assert.doesNotMatch(SOURCE, /slots\.inject\("sidebar\.footer\.action"/);
|