browserclaw 0.3.1 → 0.3.3

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.js CHANGED
@@ -742,7 +742,7 @@ async function getPageForTargetId(opts) {
742
742
  const found = await findPageByTargetId(browser, opts.targetId, opts.cdpUrl);
743
743
  if (!found) {
744
744
  if (pages.length === 1) return first;
745
- throw new Error(`Tab not found (targetId: ${opts.targetId}). Use browser.tabs() to list open tabs.`);
745
+ throw new Error("tab not found");
746
746
  }
747
747
  return found;
748
748
  }
@@ -1387,7 +1387,20 @@ var InvalidBrowserNavigationUrlError = class extends Error {
1387
1387
  function withBrowserNavigationPolicy(ssrfPolicy) {
1388
1388
  return { ssrfPolicy };
1389
1389
  }
1390
+ var NETWORK_NAVIGATION_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
1391
+ var SAFE_NON_NETWORK_URLS = /* @__PURE__ */ new Set(["about:blank"]);
1390
1392
  async function assertBrowserNavigationAllowed(opts) {
1393
+ const rawUrl = String(opts.url ?? "").trim();
1394
+ let parsed;
1395
+ try {
1396
+ parsed = new URL(rawUrl);
1397
+ } catch {
1398
+ throw new InvalidBrowserNavigationUrlError(`Invalid URL: "${rawUrl}"`);
1399
+ }
1400
+ if (!NETWORK_NAVIGATION_PROTOCOLS.has(parsed.protocol)) {
1401
+ if (SAFE_NON_NETWORK_URLS.has(parsed.href)) return;
1402
+ throw new InvalidBrowserNavigationUrlError(`Navigation blocked: unsupported protocol "${parsed.protocol}"`);
1403
+ }
1391
1404
  const policy = opts.ssrfPolicy;
1392
1405
  if (policy?.allowPrivateNetwork) return;
1393
1406
  const allowedHostnames = [
@@ -1395,18 +1408,12 @@ async function assertBrowserNavigationAllowed(opts) {
1395
1408
  ...policy?.hostnameAllowlist ?? []
1396
1409
  ];
1397
1410
  if (allowedHostnames.length) {
1398
- let parsed;
1399
- try {
1400
- parsed = new URL(opts.url);
1401
- } catch {
1402
- throw new InvalidBrowserNavigationUrlError(`Invalid URL: "${opts.url}"`);
1403
- }
1404
1411
  const hostname = parsed.hostname.toLowerCase();
1405
1412
  if (allowedHostnames.some((h) => h.toLowerCase() === hostname)) return;
1406
1413
  }
1407
- if (await isInternalUrlResolved(opts.url, opts.lookupFn)) {
1414
+ if (await isInternalUrlResolved(rawUrl, opts.lookupFn)) {
1408
1415
  throw new InvalidBrowserNavigationUrlError(
1409
- `Navigation to internal/loopback address blocked: "${opts.url}". Use ssrfPolicy: { allowPrivateNetwork: true } if this is intentional.`
1416
+ `Navigation to internal/loopback address blocked: "${rawUrl}". Use ssrfPolicy: { allowPrivateNetwork: true } if this is intentional.`
1410
1417
  );
1411
1418
  }
1412
1419
  }