@mrrisega/dsh-remote 0.6.0-beta.7 → 0.6.0-beta.8
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 +30 -0
- package/clients/dsh-remote/dsh-bridge.mjs +291 -4
- package/clients/dsh-remote/e2ee-client.mjs +711 -0
- package/clients/dsh-remote/e2ee-shim-script.js +697 -0
- package/clients/dsh-remote/e2ee-shim.mjs +158 -0
- package/clients/dsh-remote/test/e2ee-bridge.test.mjs +630 -0
- package/clients/dsh-remote/test/e2ee-client.test.mjs +365 -0
- package/clients/dsh-remote/test/e2ee-shim.test.mjs +507 -0
- package/clients/dsh-remote/test/e2ee-wecrypto-parity.test.mjs +200 -0
- package/clients/dsh-remote/test/lib-e2ee-shim.mjs +59 -0
- package/clients/dsh-remote/test/lib-native-e2ee.mjs +92 -0
- package/package.json +2 -2
- package/packages/dsh-remote-web/lib/client.js +36 -1
- package/packages/dsh-remote-web/lib/index.js +29 -1
- package/packages/dsh-remote-web/test/e2ee-state.test.mjs +141 -0
- package/packages/dsh-remote-web/test/remote-access-ui.test.mjs +75 -0
- package/packages/dsh-remote-web/test/settings-entry.test.mjs +1 -1
|
@@ -251,3 +251,78 @@ test("二维码缺失容错 + 未登录引导文案(源码级约束)", () =>
|
|
|
251
251
|
assert.match(SOURCE, /带登录态/);
|
|
252
252
|
assert.match(SOURCE, /通过手机或另一台电脑远程使用同一份 dsh web/);
|
|
253
253
|
});
|
|
254
|
+
|
|
255
|
+
// ---------- 端到端加密(E2EE,Phase-5)状态徽标 ----------
|
|
256
|
+
|
|
257
|
+
const E2EE_STATE = {
|
|
258
|
+
enabled: { enabled: true, reason: "ok", profile: "pbkdf2-sha256-600k", epoch: 1, caps: ["e2ee-v2"] },
|
|
259
|
+
serverDisabled: { enabled: false, reason: "server_disabled", profile: "", epoch: 0, caps: [] },
|
|
260
|
+
paramsUnreachable: { enabled: false, reason: "params_unreachable", profile: "", epoch: 0, caps: [] },
|
|
261
|
+
localDisabled: { enabled: false, reason: "disabled_by_config", profile: "", epoch: 0, caps: [] },
|
|
262
|
+
deriveFailed: { enabled: false, reason: "derive_failed", profile: "", epoch: 0, caps: [] },
|
|
263
|
+
unknownReason: { enabled: false, reason: "brand_new_reason_x", profile: "", epoch: 0, caps: [] },
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
function stateWith(service) {
|
|
267
|
+
return { config: { phone: "13800000000", deviceId: "dev-x", mode: "saas" }, service, remoteUrl: "https://app.test/" };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function e2eeLine(tree) {
|
|
271
|
+
return find(tree, (n) => n.props && typeof n.props.className === "string" && n.props.className.indexOf("dru-e2ee-line") === 0);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
test("E2EE 徽标:已启用 → “🔒 端到端加密已启用(手机解锁后生效)”(service.e2ee 字段驱动)", () => {
|
|
275
|
+
const plugin = loadPlugin();
|
|
276
|
+
plugin.states[0] = stateWith({ running: true, e2ee: E2EE_STATE.enabled });
|
|
277
|
+
const tree = plugin.render();
|
|
278
|
+
const line = e2eeLine(tree);
|
|
279
|
+
assert.ok(line, "启用态应在「📱 远程访问」卡渲染加密状态行");
|
|
280
|
+
assert.match(String(line.props.className), /ok/, "启用态状态行应为绿色(ok)标记");
|
|
281
|
+
assert.ok(textHas(tree, "🔒 端到端加密已启用"), "应显示“端到端加密已启用”徽标文案");
|
|
282
|
+
assert.ok(textHas(tree, "手机解锁后生效"), "应提示“手机解锁后生效”(bridge 就绪、手机解锁后方生效)");
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("E2EE 徽标:未启用原因映射可读文案(灰度等待 / 参数不可达 / 本地关闭 / 改密 / 未知兜底)", () => {
|
|
286
|
+
const cases = [
|
|
287
|
+
[E2EE_STATE.serverDisabled, "等待服务端开启 E2EE"],
|
|
288
|
+
[E2EE_STATE.paramsUnreachable, "当前为普通安全连接(HTTPS)"],
|
|
289
|
+
[E2EE_STATE.localDisabled, "当前为普通安全连接(HTTPS)"],
|
|
290
|
+
[E2EE_STATE.deriveFailed, "账号密码已变更"],
|
|
291
|
+
[E2EE_STATE.unknownReason, "当前为普通安全连接(HTTPS)"], // 未知 reason → 兜底
|
|
292
|
+
];
|
|
293
|
+
for (const [e2ee, text] of cases) {
|
|
294
|
+
const plugin = loadPlugin();
|
|
295
|
+
plugin.states[0] = stateWith({ running: true, e2ee });
|
|
296
|
+
const tree = plugin.render();
|
|
297
|
+
assert.ok(textHas(tree, text), `reason=${e2ee.reason} 应映射为可读文案: ${text}`);
|
|
298
|
+
const line = e2eeLine(tree);
|
|
299
|
+
assert.ok(line && !/ ok/.test(String(line.props.className)), `reason=${e2ee.reason} 非启用态不应带 ok 标记`);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test("E2EE 徽标:未登录 / host 未下发 e2ee → 不打扰(不渲染状态行)", () => {
|
|
304
|
+
// 未登录(config 无 phone)即便 bridge 上报 enabled 也不打扰
|
|
305
|
+
const anon = loadPlugin();
|
|
306
|
+
anon.states[0] = { config: { deviceId: "dev-x", mode: "saas" }, service: { running: true, e2ee: E2EE_STATE.enabled } };
|
|
307
|
+
assert.equal(e2eeLine(anon.render()), undefined, "未登录不应渲染 E2EE 状态行");
|
|
308
|
+
assert.ok(!textHas(anon.render(), "手机解锁后生效"), "未登录不应出现加密徽标文案");
|
|
309
|
+
|
|
310
|
+
// 已登录但 service 无 e2ee(旧 host / 未下发)→ 不渲染
|
|
311
|
+
const oldHost = loadPlugin();
|
|
312
|
+
oldHost.states[0] = stateWith({ running: true });
|
|
313
|
+
assert.equal(e2eeLine(oldHost.render()), undefined, "未下发 service.e2ee 时不应渲染状态行");
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
test("E2EE 徽标(源码级约束):client 含徽标字段/文案与 reason 映射表", () => {
|
|
317
|
+
assert.match(SOURCE, /service\.e2ee/);
|
|
318
|
+
assert.match(SOURCE, /\.e2ee-state\.json/);
|
|
319
|
+
assert.match(SOURCE, /端到端加密已启用(手机解锁后生效)/);
|
|
320
|
+
assert.match(SOURCE, /等待服务端开启 E2EE(灰度中,当前为加密准备)/);
|
|
321
|
+
assert.match(SOURCE, /当前为普通安全连接(HTTPS)/);
|
|
322
|
+
assert.match(SOURCE, /server_disabled/);
|
|
323
|
+
assert.match(SOURCE, /params_unreachable/);
|
|
324
|
+
assert.match(SOURCE, /disabled_by_config/);
|
|
325
|
+
assert.match(SOURCE, /derive_failed/);
|
|
326
|
+
assert.match(SOURCE, /describeE2ee/);
|
|
327
|
+
assert.match(SOURCE, /dru-e2ee-line/);
|
|
328
|
+
});
|
|
@@ -203,7 +203,7 @@ test("登录态账号区:无「切换账号」,有「退出登录」,头
|
|
|
203
203
|
"📱 远程访问:用手机或另一台电脑的浏览器,随时随地使用同一份 dsh web——人在哪都能用(免公网 IP、免内网穿透);官方托管中继,4G/5G 即用,也可自建服务。",
|
|
204
204
|
"🛠 电脑端一键安装:bridge 与「远程访问」面板一次到位——云端/自建切换、账号登录、bridge 启停、一次性扫码访问、已授权设备管理、意见反馈都在这里。",
|
|
205
205
|
"🔒 安全与通道:HTTP / WebSocket 全量透传,一次性访问密钥认证,面板实时显示设备与已授权设备列表;服务端可配置流量配额。",
|
|
206
|
-
"🛡
|
|
206
|
+
"🛡 端到端加密(灰度开启中):服务端开启后,手机↔电脑之间的消息内容用「你的账号密码派生密钥」端到端加密——密钥与密码不落服务端(仅存校验值),中继只可见路径/大小/时间(详见 README「安全与隐私」)。",
|
|
207
207
|
];
|
|
208
208
|
for (const p of points) {
|
|
209
209
|
assert.ok(find(tree, (n) => n.children?.includes(p)), `说明卡片应含要点: ${p.slice(0, 12)}…`);
|