browserclaw 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -9,10 +9,19 @@ interface FrameEvalResult {
9
9
 
10
10
  /**
11
11
  * Policy for controlling which URLs browser navigation is allowed to reach.
12
- * By default all private/internal addresses are blocked to prevent SSRF attacks.
12
+ * Defaults to trusted-network mode (private/internal addresses allowed).
13
+ * Set `dangerouslyAllowPrivateNetwork: false` to enforce strict public-only checks.
13
14
  */
14
15
  interface SsrfPolicy {
15
- /** Allow navigation to private/internal network addresses. Default: `false` */
16
+ /**
17
+ * Allow navigation to private/internal network addresses.
18
+ * Default: `true` (trusted-network mode). Set to `false` for strict public-only enforcement.
19
+ */
20
+ dangerouslyAllowPrivateNetwork?: boolean;
21
+ /**
22
+ * Allow navigation to private/internal network addresses.
23
+ * @deprecated Use `dangerouslyAllowPrivateNetwork` instead.
24
+ */
16
25
  allowPrivateNetwork?: boolean;
17
26
  /** Hostnames explicitly allowed even if they resolve to private addresses */
18
27
  allowedHostnames?: string[];
@@ -48,12 +57,13 @@ interface LaunchOptions {
48
57
  chromeArgs?: string[];
49
58
  /**
50
59
  * SSRF policy controlling which URLs navigation is allowed to reach.
51
- * By default all private/internal addresses are blocked.
60
+ * Defaults to trusted-network mode (private/internal addresses allowed).
61
+ * Set `dangerouslyAllowPrivateNetwork: false` to enforce strict public-only checks.
52
62
  */
53
63
  ssrfPolicy?: SsrfPolicy;
54
64
  /**
55
65
  * Allow navigation to internal/loopback addresses (localhost, 127.x, private IPs).
56
- * @deprecated Use `ssrfPolicy: { allowPrivateNetwork: true }` instead.
66
+ * @deprecated Use `ssrfPolicy: { dangerouslyAllowPrivateNetwork: true }` instead.
57
67
  */
58
68
  allowInternal?: boolean;
59
69
  }
@@ -61,12 +71,13 @@ interface LaunchOptions {
61
71
  interface ConnectOptions {
62
72
  /**
63
73
  * SSRF policy controlling which URLs navigation is allowed to reach.
64
- * By default all private/internal addresses are blocked.
74
+ * Defaults to trusted-network mode (private/internal addresses allowed).
75
+ * Set `dangerouslyAllowPrivateNetwork: false` to enforce strict public-only checks.
65
76
  */
66
77
  ssrfPolicy?: SsrfPolicy;
67
78
  /**
68
79
  * Allow navigation to internal/loopback addresses (localhost, 127.x, private IPs).
69
- * @deprecated Use `ssrfPolicy: { allowPrivateNetwork: true }` instead.
80
+ * @deprecated Use `ssrfPolicy: { dangerouslyAllowPrivateNetwork: true }` instead.
70
81
  */
71
82
  allowInternal?: boolean;
72
83
  /**
package/dist/index.d.ts CHANGED
@@ -9,10 +9,19 @@ interface FrameEvalResult {
9
9
 
10
10
  /**
11
11
  * Policy for controlling which URLs browser navigation is allowed to reach.
12
- * By default all private/internal addresses are blocked to prevent SSRF attacks.
12
+ * Defaults to trusted-network mode (private/internal addresses allowed).
13
+ * Set `dangerouslyAllowPrivateNetwork: false` to enforce strict public-only checks.
13
14
  */
14
15
  interface SsrfPolicy {
15
- /** Allow navigation to private/internal network addresses. Default: `false` */
16
+ /**
17
+ * Allow navigation to private/internal network addresses.
18
+ * Default: `true` (trusted-network mode). Set to `false` for strict public-only enforcement.
19
+ */
20
+ dangerouslyAllowPrivateNetwork?: boolean;
21
+ /**
22
+ * Allow navigation to private/internal network addresses.
23
+ * @deprecated Use `dangerouslyAllowPrivateNetwork` instead.
24
+ */
16
25
  allowPrivateNetwork?: boolean;
17
26
  /** Hostnames explicitly allowed even if they resolve to private addresses */
18
27
  allowedHostnames?: string[];
@@ -48,12 +57,13 @@ interface LaunchOptions {
48
57
  chromeArgs?: string[];
49
58
  /**
50
59
  * SSRF policy controlling which URLs navigation is allowed to reach.
51
- * By default all private/internal addresses are blocked.
60
+ * Defaults to trusted-network mode (private/internal addresses allowed).
61
+ * Set `dangerouslyAllowPrivateNetwork: false` to enforce strict public-only checks.
52
62
  */
53
63
  ssrfPolicy?: SsrfPolicy;
54
64
  /**
55
65
  * Allow navigation to internal/loopback addresses (localhost, 127.x, private IPs).
56
- * @deprecated Use `ssrfPolicy: { allowPrivateNetwork: true }` instead.
66
+ * @deprecated Use `ssrfPolicy: { dangerouslyAllowPrivateNetwork: true }` instead.
57
67
  */
58
68
  allowInternal?: boolean;
59
69
  }
@@ -61,12 +71,13 @@ interface LaunchOptions {
61
71
  interface ConnectOptions {
62
72
  /**
63
73
  * SSRF policy controlling which URLs navigation is allowed to reach.
64
- * By default all private/internal addresses are blocked.
74
+ * Defaults to trusted-network mode (private/internal addresses allowed).
75
+ * Set `dangerouslyAllowPrivateNetwork: false` to enforce strict public-only checks.
65
76
  */
66
77
  ssrfPolicy?: SsrfPolicy;
67
78
  /**
68
79
  * Allow navigation to internal/loopback addresses (localhost, 127.x, private IPs).
69
- * @deprecated Use `ssrfPolicy: { allowPrivateNetwork: true }` instead.
80
+ * @deprecated Use `ssrfPolicy: { dangerouslyAllowPrivateNetwork: true }` instead.
70
81
  */
71
82
  allowInternal?: boolean;
72
83
  /**
package/dist/index.js CHANGED
@@ -346,7 +346,9 @@ async function isChromeReachable(cdpUrl, timeoutMs = 500, authToken) {
346
346
  const headers = {};
347
347
  if (authToken) headers["Authorization"] = `Bearer ${authToken}`;
348
348
  const res = await fetch(`${cdpUrl.replace(/\/+$/, "")}/json/version`, { signal: ctrl.signal, headers });
349
- return res.ok;
349
+ if (!res.ok) return false;
350
+ const data = await res.json();
351
+ return data != null && typeof data === "object";
350
352
  } catch {
351
353
  return false;
352
354
  } finally {
@@ -362,6 +364,7 @@ async function getChromeWebSocketUrl(cdpUrl, timeoutMs = 500, authToken) {
362
364
  const res = await fetch(`${cdpUrl.replace(/\/+$/, "")}/json/version`, { signal: ctrl.signal, headers });
363
365
  if (!res.ok) return null;
364
366
  const data = await res.json();
367
+ if (!data || typeof data !== "object") return null;
365
368
  return String(data?.webSocketDebuggerUrl ?? "").trim() || null;
366
369
  } catch {
367
370
  return null;
@@ -1403,7 +1406,7 @@ async function assertBrowserNavigationAllowed(opts) {
1403
1406
  throw new InvalidBrowserNavigationUrlError(`Navigation blocked: unsupported protocol "${parsed.protocol}"`);
1404
1407
  }
1405
1408
  const policy = opts.ssrfPolicy;
1406
- if (policy?.allowPrivateNetwork) return;
1409
+ if (policy?.dangerouslyAllowPrivateNetwork ?? policy?.allowPrivateNetwork ?? true) return;
1407
1410
  const allowedHostnames = [
1408
1411
  ...policy?.allowedHostnames ?? [],
1409
1412
  ...policy?.hostnameAllowlist ?? []
@@ -1414,7 +1417,7 @@ async function assertBrowserNavigationAllowed(opts) {
1414
1417
  }
1415
1418
  if (await isInternalUrlResolved(rawUrl, opts.lookupFn)) {
1416
1419
  throw new InvalidBrowserNavigationUrlError(
1417
- `Navigation to internal/loopback address blocked: "${rawUrl}". Use ssrfPolicy: { allowPrivateNetwork: true } if this is intentional.`
1420
+ `Navigation to internal/loopback address blocked: "${rawUrl}". ssrfPolicy.dangerouslyAllowPrivateNetwork is false (strict mode).`
1418
1421
  );
1419
1422
  }
1420
1423
  }
@@ -1561,7 +1564,7 @@ async function isInternalUrlResolved(url, lookupFn = lookup) {
1561
1564
  async function navigateViaPlaywright(opts) {
1562
1565
  const url = String(opts.url ?? "").trim();
1563
1566
  if (!url) throw new Error("url is required");
1564
- const policy = opts.allowInternal ? { ...opts.ssrfPolicy, allowPrivateNetwork: true } : opts.ssrfPolicy;
1567
+ const policy = opts.allowInternal ? { ...opts.ssrfPolicy, dangerouslyAllowPrivateNetwork: true } : opts.ssrfPolicy;
1565
1568
  await assertBrowserNavigationAllowed({ url, ssrfPolicy: policy });
1566
1569
  const page = await getPageForTargetId({ cdpUrl: opts.cdpUrl, targetId: opts.targetId });
1567
1570
  ensurePageState(page);
@@ -1586,7 +1589,7 @@ async function listPagesViaPlaywright(opts) {
1586
1589
  async function createPageViaPlaywright(opts) {
1587
1590
  const targetUrl = (opts.url ?? "").trim() || "about:blank";
1588
1591
  if (targetUrl !== "about:blank") {
1589
- const policy = opts.allowInternal ? { ...opts.ssrfPolicy, allowPrivateNetwork: true } : opts.ssrfPolicy;
1592
+ const policy = opts.allowInternal ? { ...opts.ssrfPolicy, dangerouslyAllowPrivateNetwork: true } : opts.ssrfPolicy;
1590
1593
  await assertBrowserNavigationAllowed({ url: targetUrl, ssrfPolicy: policy });
1591
1594
  }
1592
1595
  const { browser } = await connectBrowser(opts.cdpUrl);
@@ -3010,7 +3013,7 @@ var BrowserClaw = class _BrowserClaw {
3010
3013
  static async launch(opts = {}) {
3011
3014
  const chrome = await launchChrome(opts);
3012
3015
  const cdpUrl = `http://127.0.0.1:${chrome.cdpPort}`;
3013
- const ssrfPolicy = opts.allowInternal ? { ...opts.ssrfPolicy, allowPrivateNetwork: true } : opts.ssrfPolicy;
3016
+ const ssrfPolicy = opts.allowInternal ? { ...opts.ssrfPolicy, dangerouslyAllowPrivateNetwork: true } : opts.ssrfPolicy;
3014
3017
  return new _BrowserClaw(cdpUrl, chrome, ssrfPolicy);
3015
3018
  }
3016
3019
  /**
@@ -3032,7 +3035,7 @@ var BrowserClaw = class _BrowserClaw {
3032
3035
  throw new Error(`Cannot connect to Chrome at ${cdpUrl}. Is Chrome running with --remote-debugging-port?`);
3033
3036
  }
3034
3037
  await connectBrowser(cdpUrl, opts?.authToken);
3035
- const ssrfPolicy = opts?.allowInternal ? { ...opts.ssrfPolicy, allowPrivateNetwork: true } : opts?.ssrfPolicy;
3038
+ const ssrfPolicy = opts?.allowInternal ? { ...opts.ssrfPolicy, dangerouslyAllowPrivateNetwork: true } : opts?.ssrfPolicy;
3036
3039
  return new _BrowserClaw(cdpUrl, null, ssrfPolicy);
3037
3040
  }
3038
3041
  /**