{"record":{"id":"d3820275e79838c1","repo":"BigPizzaV3/CodexPlusPlus","slug":"webcrypto","errorCode":null,"errorMessage":"当前页面不是安全上下文，WebCrypto 不可用","messagePattern":"当前页面不是安全上下文，WebCrypto 不可用","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/codex-plus-mobile-relay/src/main.rs","lineNumber":792,"sourceCode":"const params = new URLSearchParams(location.search);\nconst statusEl = $(\"status\");\nconst sessionsEl = $(\"sessions\");\nconst messagesEl = $(\"messages\");\nconst titleEl = $(\"threadTitle\");\nconst metaEl = $(\"threadMeta\");\nconst sessionsPane = $(\"sessionsPane\");\nconst detailPane = $(\"detailPane\");\nfunction setStatus(text, error = false) { statusEl.textContent = text; statusEl.classList.toggle(\"error\", error); }\nfunction b64url(bytes) {\n  let text = btoa(String.fromCharCode(...new Uint8Array(bytes)));\n  return text.replaceAll(\"+\", \"-\").replaceAll(\"/\", \"_\").replace(/=+$/g, \"\");\n}\nfunction b64urlDecode(text) {\n  const padded = text.replaceAll(\"-\", \"+\").replaceAll(\"_\", \"/\") + \"===\".slice((text.length + 3) % 4);\n  return Uint8Array.from(atob(padded), ch => ch.charCodeAt(0));\n}\nasync function cryptoKey() {\n  if (!crypto?.subtle) throw new Error(\"当前页面不是安全上下文，WebCrypto 不可用\");\n  const raw = new TextEncoder().encode($(\"key\").value);\n  const digest = await crypto.subtle.digest(\"SHA-256\", raw);\n  return crypto.subtle.importKey(\"raw\", digest, \"AES-GCM\", false, [\"encrypt\", \"decrypt\"]);\n}\nasync function encrypt(payload) {\n  if (!crypto?.subtle) {\n    setStatus(\"当前浏览器禁用 WebCrypto，已使用兼容模式\", true);\n    return { type: \"plaintext\", payload };\n  }\n  const key = await cryptoKey();\n  const nonce = crypto.getRandomValues(new Uint8Array(12));\n  const plain = new TextEncoder().encode(JSON.stringify(payload));\n  const encrypted = await crypto.subtle.encrypt({ name: \"AES-GCM\", iv: nonce }, key, plain);\n  return { type: \"encrypted\", nonce: b64url(nonce), payload: b64url(encrypted) };\n}\nasync function decrypt(envelope) {\n  if (envelope?.type === \"plaintext\") return envelope.payload;\n  if (!envelope || envelope.type !== \"encrypted\") throw new Error(\"收到未加密数据包\");","sourceCodeStart":774,"sourceCodeEnd":810,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/f2074595a281bc057525c748175c8eb9805b0673/apps/codex-plus-mobile-relay/src/main.rs#L774-L810","documentation":"Client-side error in the mobile relay web page (mobile_relay_page): the page is not in a secure context (not HTTPS/localhost), so crypto.subtle is unavailable and the AES-GCM key for relay communication cannot be derived. Fired by the browser's WebCrypto secure-context restriction.","triggerScenarios":"Thrown at apps/codex-plus-mobile-relay/src/main.rs:792 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Open the relay page via https:// or http://localhost","Serve the relay behind a TLS-terminating proxy","Use a browser permitting WebCrypto on the origin"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"f2074595a281bc057525c748175c8eb9805b0673","analyzedAt":"2026-08-23T12:52:24.489Z","contentChangedAt":"2026-08-23T12:52:24.489Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}