tao-shen Claude Opus 4.6 commited on
Commit
7b4c5b7
·
1 Parent(s): 3925157

fix: use global variable for token injection (works in incognito iframe)

Browse files

When HF Spaces embeds the Control UI in an iframe, Chrome incognito
blocks third-party localStorage access. The token injection via
localStorage silently fails, leaving the UI unable to authenticate.

Changes:
- Add source patch: storage.ts reads window.__OPENCLAW_AUTH_TOKEN__
as fallback when localStorage token is empty/unavailable
- inject-token.sh: set window.__OPENCLAW_AUTH_TOKEN__ global variable
in addition to localStorage (global always works)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

patches/hf-spaces-global-token-fallback.patch ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ diff --git a/ui/src/ui/storage.ts b/ui/src/ui/storage.ts
2
+ index b32e6c3..763a543 100644
3
+ --- a/ui/src/ui/storage.ts
4
+ +++ b/ui/src/ui/storage.ts
5
+ @@ -17,6 +17,14 @@ export type UiSettings = {
6
+ locale?: string;
7
+ };
8
+
9
+ +// Read an injected auth token from a global variable.
10
+ +// Used by HF Spaces where localStorage may be unavailable
11
+ +// (e.g. third-party iframe in incognito mode).
12
+ +function getInjectedToken(): string {
13
+ + const w = globalThis as Record<string, unknown>;
14
+ + return typeof w.__OPENCLAW_AUTH_TOKEN__ === "string" ? (w.__OPENCLAW_AUTH_TOKEN__ as string) : "";
15
+ +}
16
+ +
17
+ export function loadSettings(): UiSettings {
18
+ const defaultUrl = (() => {
19
+ const proto = location.protocol === "https:" ? "wss" : "ws";
20
+ @@ -25,7 +33,7 @@ export function loadSettings(): UiSettings {
21
+
22
+ const defaults: UiSettings = {
23
+ gatewayUrl: defaultUrl,
24
+ - token: "",
25
+ + token: getInjectedToken(),
26
+ sessionKey: "main",
27
+ lastActiveSessionKey: "main",
28
+ theme: "system",
29
+ @@ -47,7 +55,7 @@ export function loadSettings(): UiSettings {
30
+ typeof parsed.gatewayUrl === "string" && parsed.gatewayUrl.trim()
31
+ ? parsed.gatewayUrl.trim()
32
+ : defaults.gatewayUrl,
33
+ - token: typeof parsed.token === "string" ? parsed.token : defaults.token,
34
+ + token: typeof parsed.token === "string" && parsed.token ? parsed.token : defaults.token,
35
+ sessionKey:
36
+ typeof parsed.sessionKey === "string" && parsed.sessionKey.trim()
37
+ ? parsed.sessionKey.trim()
scripts/inject-token.sh CHANGED
@@ -11,7 +11,9 @@ if [ ! -f "$INDEX_HTML" ]; then
11
  fi
12
 
13
  # Create the injection script
14
- INJECT_SCRIPT="<script>!function(){var K='openclaw.control.settings.v1';try{var s=JSON.parse(localStorage.getItem(K)||'{}');s.token='${TOKEN}';localStorage.setItem(K,JSON.stringify(s))}catch(e){}}()</script>"
 
 
15
 
16
  # Use python3 for reliable string replacement (avoids sed delimiter issues)
17
  python3 -c "
@@ -20,7 +22,7 @@ f = '${INDEX_HTML}'
20
  with open(f, 'r') as fh:
21
  html = fh.read()
22
  inject = '''${INJECT_SCRIPT}'''
23
- if '</head>' in html and inject not in html:
24
  html = html.replace('</head>', inject + '</head>')
25
  with open(f, 'w') as fh:
26
  fh.write(html)
 
11
  fi
12
 
13
  # Create the injection script
14
+ # 1. Set window.__OPENCLAW_AUTH_TOKEN__ — always works (even when localStorage is blocked in iframe/incognito)
15
+ # 2. Also try localStorage as a fallback for the original UI code path
16
+ INJECT_SCRIPT="<script>window.__OPENCLAW_AUTH_TOKEN__='${TOKEN}';try{var K='openclaw.control.settings.v1',s=JSON.parse(localStorage.getItem(K)||'{}');s.token='${TOKEN}';localStorage.setItem(K,JSON.stringify(s))}catch(e){}</script>"
17
 
18
  # Use python3 for reliable string replacement (avoids sed delimiter issues)
19
  python3 -c "
 
22
  with open(f, 'r') as fh:
23
  html = fh.read()
24
  inject = '''${INJECT_SCRIPT}'''
25
+ if '</head>' in html and '__OPENCLAW_AUTH_TOKEN__' not in html:
26
  html = html.replace('</head>', inject + '</head>')
27
  with open(f, 'w') as fh:
28
  fh.write(html)