somratpro commited on
Commit
a0b9abe
Β·
1 Parent(s): f0bf522

fix: patch OpenClaw scope-clearing bug and refactor WhatsApp session logout logic to error handler

Browse files
Files changed (2) hide show
  1. start.sh +35 -0
  2. wa-guardian.js +17 -44
start.sh CHANGED
@@ -264,6 +264,41 @@ chmod 600 /home/node/.openclaw/openclaw.json
264
  # This preload script keeps iframe embedding working on HF Spaces.
265
  export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--require /home/node/app/iframe-fix.cjs"
266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  # ── Startup Summary ──
268
  echo ""
269
  echo " β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”"
 
264
  # This preload script keeps iframe embedding working on HF Spaces.
265
  export NODE_OPTIONS="${NODE_OPTIONS:+$NODE_OPTIONS }--require /home/node/app/iframe-fix.cjs"
266
 
267
+ # ── Patch OpenClaw scope-clearing bug for headless HF auth ──
268
+ # OpenClaw can clear requested operator scopes after allowing a token-auth
269
+ # connection without device identity, which breaks the WhatsApp guardian's
270
+ # web.login.wait / channels.status calls on Spaces.
271
+ patch_openclaw_scope_bug() {
272
+ local roots=(
273
+ "/home/node/.openclaw/openclaw-app"
274
+ "/usr/local/lib/node_modules/openclaw"
275
+ )
276
+ local target=""
277
+ local updated=0
278
+
279
+ for root in "${roots[@]}"; do
280
+ [ -d "$root/dist" ] || continue
281
+ target=$(find "$root/dist" -maxdepth 1 -type f -name 'gateway-cli-*.js' | head -n 1)
282
+ [ -n "$target" ] || continue
283
+
284
+ if grep -q 'return params.decision.kind !== "allow" || !params.controlUiAuthPolicy.allowBypass' "$target"; then
285
+ perl -0pi -e 's@return params\.decision\.kind !== "allow" \|\| !params\.controlUiAuthPolicy\.allowBypass && !params\.preserveInsecureLocalControlUiScopes && \(params\.authMethod === "token" \|\| params\.authMethod === "password" \|\| params\.authMethod === "trusted-proxy" \|\| params\.trustedProxyAuthOk === true\);@return params.decision.kind !== "allow";@g' "$target"
286
+
287
+ if grep -q 'return params.decision.kind !== "allow";' "$target"; then
288
+ echo "πŸ”§ Patched OpenClaw scope-clearing bug in $(basename "$target")"
289
+ updated=1
290
+ break
291
+ fi
292
+ fi
293
+ done
294
+
295
+ if [ "$updated" -eq 0 ]; then
296
+ echo "⚠️ OpenClaw scope patch not applied (bundle format may have changed)"
297
+ fi
298
+ }
299
+
300
+ patch_openclaw_scope_bug
301
+
302
  # ── Startup Summary ──
303
  echo ""
304
  echo " β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”"
wa-guardian.js CHANGED
@@ -121,50 +121,6 @@ async function checkStatus() {
121
  let ws;
122
  try {
123
  ws = await createConnection();
124
-
125
- // Check if WhatsApp channel exists and its status
126
- const statusRes = await callRpc(ws, "channels.status", {});
127
- const channels = (statusRes.payload || statusRes.result)?.channels || {};
128
- const wa = channels.whatsapp;
129
-
130
- if (!wa) {
131
- ws.close();
132
- return;
133
- }
134
-
135
- const lastError = String(wa.lastError || "").toLowerCase();
136
- const recentlySaw515 = Date.now() - last515At < POST_515_NO_LOGOUT_MS;
137
- const needsLogout = wa.linked && !wa.connected && !recentlySaw515 &&
138
- (
139
- lastError.includes("401") ||
140
- lastError.includes("unauthorized") ||
141
- lastError.includes("logged out") ||
142
- lastError.includes("440") ||
143
- lastError.includes("conflict")
144
- );
145
-
146
- if (needsLogout) {
147
- console.log("[guardian] Clearing invalid WhatsApp session so a fresh QR can be used...");
148
- try {
149
- await callRpc(ws, "channels.logout", { channel: "whatsapp" });
150
- writeResetMarker();
151
- hasShownWaitMessage = false;
152
- console.log("[guardian] Logged out invalid WhatsApp session.");
153
- } catch (error) {
154
- console.log(`[guardian] Failed to log out invalid session: ${error.message}`);
155
- }
156
- ws.close();
157
- return;
158
- }
159
-
160
- // If connected, we are good
161
- if (wa.connected) {
162
- hasShownWaitMessage = false;
163
- ws.close();
164
- return;
165
- }
166
-
167
- // If "Ready to pair", we wait for the scan
168
  isWaiting = true;
169
  if (!hasShownWaitMessage) {
170
  console.log("\n[guardian] πŸ“± WhatsApp pairing in progress. Please scan the QR code in the Control UI.");
@@ -200,6 +156,23 @@ async function checkStatus() {
200
  }
201
 
202
  } catch (e) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  // Normal timeout or gateway starting up; retry on the next interval.
204
  } finally {
205
  isWaiting = false;
 
121
  let ws;
122
  try {
123
  ws = await createConnection();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  isWaiting = true;
125
  if (!hasShownWaitMessage) {
126
  console.log("\n[guardian] πŸ“± WhatsApp pairing in progress. Please scan the QR code in the Control UI.");
 
156
  }
157
 
158
  } catch (e) {
159
+ const message = e && e.message ? e.message : "";
160
+ if (
161
+ /401|unauthorized|logged out|440|conflict/i.test(message) &&
162
+ Date.now() - last515At >= POST_515_NO_LOGOUT_MS
163
+ ) {
164
+ console.log("[guardian] Clearing invalid WhatsApp session so a fresh QR can be used...");
165
+ try {
166
+ if (ws) {
167
+ await callRpc(ws, "channels.logout", { channel: "whatsapp" });
168
+ writeResetMarker();
169
+ hasShownWaitMessage = false;
170
+ console.log("[guardian] Logged out invalid WhatsApp session.");
171
+ }
172
+ } catch (error) {
173
+ console.log(`[guardian] Failed to log out invalid session: ${error.message}`);
174
+ }
175
+ }
176
  // Normal timeout or gateway starting up; retry on the next interval.
177
  } finally {
178
  isWaiting = false;