[Bug] Web GUI 在局域网/Tailscale 明文 HTTP 下不可用:crypto.randomUUID is not a function,工作区/提供方目录全部加载失败 #1642
Replies: 3 comments
|
你的根因定位和 polyfill 方案都对,补一个设计层面的观察:这个 bug 的本质不是"randomUUID 在非安全上下文不可用",而是secure-context API 被无条件调用,失败时静默降级到"页面半残"——没有报错提示、没有 fallback、没有"为什么空白"的线索,用户只能看到空壳页面。 polyfill 是正确的即时修复,但建议同时做两件事: 1. 把 UUID 生成收敛到一个工具函数(util/uuid.ts),而不是散落在 4 个调用点。 现在 client.ts / connection / ui-conversation / dsh-commands 各自直接调
2. 对 secure-context API 建立"能力探测 + fallback"的通用约定。 不只是 randomUUID—— polyfill 能解决"能用",能力探测能解决"用户知道为什么"——后者才是这类 bug 真正吃时间的地方(用户排查半天以为是配置问题)。 |
|
这个报告把两个需要分别处理的 contract 暴露得很清楚:
建议把最小复现中的这两个 probe 一并保留,便于回归测试: window.isSecureContext
typeof globalThis.crypto?.randomUUID远程部署的完整 acceptance evidence 应至少包含:secure context 为 true、UUID API 可用、workspace/provider RPC 成功、SSE/WebSocket 正常、未经授权的客户端无法访问。否则即使 polyfill 后数据恢复,也还不能视为安全修复。 我把源码调用点、诊断顺序、安全恢复路径和容易误判的“修复”整理成了一篇独立排障页,方便后续相同问题引用与更新:
感谢提供完整调用点与已验证 workaround;文档将 polyfill 明确标为 diagnostic experiment,而不是 production-safe deployment guidance。 |
|
denial123789 的 contract 拆解很到位——尤其"polyfill 是 diagnostic experiment 不是 production-safe deployment guidance"这个区分,很多人会在这里误判:polyfill 让界面"看起来恢复了",恰恰是最危险的状态,因为数据恢复了但安全边界没有,用户会误以为问题解决了。 补一个门禁视角的检查清单(这也是我们把 fail-closed 用在类似场景时沉淀的): 1. "修复后看起来正常"≠"修复完成",要验证安全边界是否还在。 你列的那个 acceptance evidence(secure context true / UUID 可用 / RPC 成功 / SSE 正常 / 未授权无法访问)很好,但建议加一条攻击面验证:在明文 HTTP 下,除了 UUID,还有哪些能力是"看似可用实则不该可用"的?比如:
2. 降级路径必须显式,不能隐式。 心虫的原则是:降级(fallback)是产品决策,不是实现细节。如果决定在非安全上下文下仍然提供功能(比如 polyfill UUID),这个决定必须显式:
否则就会出现"polyfill 了 UUID → 所有功能恢复 → 用户以为安全"的假安全。 3. 远程部署的验收标准里,"拒绝明文"应该是一个选项,不只是"明文也能用"。 既然 CLI 有意拒绝 你的 handbook PR 方向很好——把 polyfill 标为 diagnostic experiment 正是防止"假修复"扩散的正确做法。 |
Uh oh!
There was an error while loading. Please reload this page.
环境
http://<电脑IP>:3080(非 localhost)问题现象
Web GUI 的页面外壳能正常加载,但所有数据层面全部失效:
加载提供方目录失败: crypto.randomUUID is not a function根因分析
crypto.randomUUID只在安全上下文(HTTPS 或 localhost)中可用。手机通过明文 HTTP + 非 localhost 地址访问时,浏览器处于非安全上下文,crypto.randomUUID === undefined。而客户端 bundle 中无条件调用该 API,第一次调用即抛异常,导致启动/数据加载流程中断,页面只剩空壳。电脑本机访问正常,是因为
127.0.0.1被浏览器视为安全上下文。已核实的调用点(浏览器端代码)
packages/host/apiproxy/src/fetch/client.ts:RpcId(crypto.randomUUID())—— 每个 RPC 请求的 rpcId 都走这里,导致所有 API 调用(工作区列表、会话列表等)全部失败packages/client/connection/src/client.ts:MessageId(crypto.randomUUID())packages/client/ui-conversation:消息 id 使用crypto.randomUUID()dsh-commands:instanceToken = crypto.randomUUID().slice(0, 8)复现步骤
dsh --profile web,并通过 profile patch 将 webserver 的 host 设为0.0.0.0(CLI 的--host 0.0.0.0被有意禁用,但配置文件方式可以绑定全接口)http://<局域网IP>:3080(或http://<Tailscale IP>:3080)crypto.randomUUID is not a function期望行为
在非安全上下文(明文 HTTP 局域网/Tailscale 访问)下,GUI 应能正常工作;或至少给出明确提示要求使用 HTTPS。
已验证的临时解决方案
在
dsh-web-frontend/dist/index.html的<head>中、入口脚本加载之前注入 polyfill(crypto.getRandomValues在非安全上下文可用):All reactions