fix(browser): require auth on control HTTP and auto-bootstrap token

This commit is contained in:
Peter Steinberger
2026-02-13 02:01:57 +01:00
parent 85409e401b
commit 9230a2ae14
11 changed files with 634 additions and 5 deletions

View File

@@ -1,4 +1,6 @@
import { formatCliCommand } from "../cli/command-format.js";
import { loadConfig } from "../config/config.js";
import { resolveBrowserControlAuth } from "./control-auth.js";
import {
createBrowserControlContext,
startBrowserControlServiceFromConfig,
@@ -9,6 +11,42 @@ function isAbsoluteHttp(url: string): boolean {
return /^https?:\/\//i.test(url.trim());
}
function isLoopbackHttpUrl(url: string): boolean {
try {
const host = new URL(url).hostname.trim().toLowerCase();
return host === "127.0.0.1" || host === "localhost" || host === "::1";
} catch {
return false;
}
}
function withLoopbackBrowserAuth(
url: string,
init: (RequestInit & { timeoutMs?: number }) | undefined,
): RequestInit & { timeoutMs?: number } {
const headers = new Headers(init?.headers ?? {});
if (headers.has("authorization") || headers.has("x-openclaw-password")) {
return { ...init, headers };
}
if (!isLoopbackHttpUrl(url)) {
return { ...init, headers };
}
try {
const cfg = loadConfig();
const auth = resolveBrowserControlAuth(cfg);
if (auth.token) {
headers.set("Authorization", `Bearer ${auth.token}`);
} else if (auth.password) {
headers.set("x-openclaw-password", auth.password);
}
} catch {
// ignore config/auth lookup failures and continue without auth headers
}
return { ...init, headers };
}
function enhanceBrowserFetchError(url: string, err: unknown, timeoutMs: number): Error {
const hint = isAbsoluteHttp(url)
? "If this is a sandboxed session, ensure the sandbox browser is running and try again."
@@ -69,7 +107,8 @@ export async function fetchBrowserJson<T>(
const timeoutMs = init?.timeoutMs ?? 5000;
try {
if (isAbsoluteHttp(url)) {
return await fetchHttpJson<T>(url, { ...init, timeoutMs });
const httpInit = withLoopbackBrowserAuth(url, init);
return await fetchHttpJson<T>(url, { ...httpInit, timeoutMs });
}
const started = await startBrowserControlServiceFromConfig();
if (!started) {