browserclaw 0.5.0 → 0.5.1
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.cjs +49 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +49 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1524,6 +1524,22 @@ function extractEmbeddedIpv4FromIpv6(v6, opts) {
|
|
|
1524
1524
|
return true;
|
|
1525
1525
|
}
|
|
1526
1526
|
}
|
|
1527
|
+
if (parts[0] === 0 && parts[1] === 0 && parts[2] === 0 && parts[3] === 0 && parts[4] === 0 && parts[5] === 0) {
|
|
1528
|
+
const ip4str = `${parts[6] >> 8 & 255}.${parts[6] & 255}.${parts[7] >> 8 & 255}.${parts[7] & 255}`;
|
|
1529
|
+
try {
|
|
1530
|
+
return isBlockedSpecialUseIpv4Address(ipaddr__namespace.IPv4.parse(ip4str), opts);
|
|
1531
|
+
} catch {
|
|
1532
|
+
return true;
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
if ((parts[4] & 65023) === 0 && parts[5] === 24318) {
|
|
1536
|
+
const ip4str = `${parts[6] >> 8 & 255}.${parts[6] & 255}.${parts[7] >> 8 & 255}.${parts[7] & 255}`;
|
|
1537
|
+
try {
|
|
1538
|
+
return isBlockedSpecialUseIpv4Address(ipaddr__namespace.IPv4.parse(ip4str), opts);
|
|
1539
|
+
} catch {
|
|
1540
|
+
return true;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1527
1543
|
return null;
|
|
1528
1544
|
}
|
|
1529
1545
|
function isPrivateIpAddress(address, opts) {
|
|
@@ -1546,6 +1562,30 @@ function isPrivateIpAddress(address, opts) {
|
|
|
1546
1562
|
if (normalized.includes(":")) return true;
|
|
1547
1563
|
return false;
|
|
1548
1564
|
}
|
|
1565
|
+
function normalizeHostnameSet(values) {
|
|
1566
|
+
if (!values || values.length === 0) return /* @__PURE__ */ new Set();
|
|
1567
|
+
return new Set(values.map((v) => normalizeHostname(v)).filter(Boolean));
|
|
1568
|
+
}
|
|
1569
|
+
function normalizeHostnameAllowlist(values) {
|
|
1570
|
+
if (!values || values.length === 0) return [];
|
|
1571
|
+
return Array.from(
|
|
1572
|
+
new Set(
|
|
1573
|
+
values.map((v) => normalizeHostname(v)).filter((v) => v !== "*" && v !== "*." && v.length > 0)
|
|
1574
|
+
)
|
|
1575
|
+
);
|
|
1576
|
+
}
|
|
1577
|
+
function isHostnameAllowedByPattern(hostname, pattern) {
|
|
1578
|
+
if (pattern.startsWith("*.")) {
|
|
1579
|
+
const suffix = pattern.slice(2);
|
|
1580
|
+
if (!suffix || hostname === suffix) return false;
|
|
1581
|
+
return hostname.endsWith(`.${suffix}`);
|
|
1582
|
+
}
|
|
1583
|
+
return hostname === pattern;
|
|
1584
|
+
}
|
|
1585
|
+
function matchesHostnameAllowlist(hostname, allowlist) {
|
|
1586
|
+
if (allowlist.length === 0) return true;
|
|
1587
|
+
return allowlist.some((pattern) => isHostnameAllowedByPattern(hostname, pattern));
|
|
1588
|
+
}
|
|
1549
1589
|
function dedupeAndPreferIpv4(results) {
|
|
1550
1590
|
const seen = /* @__PURE__ */ new Set();
|
|
1551
1591
|
const ipv4 = [];
|
|
@@ -1591,12 +1631,15 @@ async function resolvePinnedHostnameWithPolicy(hostname, params = {}) {
|
|
|
1591
1631
|
const normalized = normalizeHostname(hostname);
|
|
1592
1632
|
if (!normalized) throw new InvalidBrowserNavigationUrlError(`Invalid hostname: "${hostname}"`);
|
|
1593
1633
|
const allowPrivateNetwork = isPrivateNetworkAllowedByPolicy(params.policy);
|
|
1594
|
-
const allowedHostnames =
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
].map((h) => normalizeHostname(h));
|
|
1598
|
-
const isExplicitlyAllowed = allowedHostnames.some((h) => h === normalized);
|
|
1634
|
+
const allowedHostnames = normalizeHostnameSet(params.policy?.allowedHostnames);
|
|
1635
|
+
const hostnameAllowlist = normalizeHostnameAllowlist(params.policy?.hostnameAllowlist);
|
|
1636
|
+
const isExplicitlyAllowed = allowedHostnames.has(normalized);
|
|
1599
1637
|
const skipPrivateNetworkChecks = allowPrivateNetwork || isExplicitlyAllowed;
|
|
1638
|
+
if (!matchesHostnameAllowlist(normalized, hostnameAllowlist)) {
|
|
1639
|
+
throw new InvalidBrowserNavigationUrlError(
|
|
1640
|
+
`Navigation blocked: hostname "${hostname}" is not in the allowlist.`
|
|
1641
|
+
);
|
|
1642
|
+
}
|
|
1600
1643
|
if (!skipPrivateNetworkChecks) {
|
|
1601
1644
|
if (isBlockedHostnameNormalized(normalized)) {
|
|
1602
1645
|
throw new InvalidBrowserNavigationUrlError(
|
|
@@ -1663,11 +1706,9 @@ async function assertBrowserNavigationAllowed(opts) {
|
|
|
1663
1706
|
"Navigation blocked: strict browser SSRF policy cannot be enforced while env proxy variables are set"
|
|
1664
1707
|
);
|
|
1665
1708
|
}
|
|
1666
|
-
const policy = opts.ssrfPolicy;
|
|
1667
|
-
if (policy?.dangerouslyAllowPrivateNetwork ?? policy?.allowPrivateNetwork ?? true) return;
|
|
1668
1709
|
await resolvePinnedHostnameWithPolicy(parsed.hostname, {
|
|
1669
1710
|
lookupFn: opts.lookupFn,
|
|
1670
|
-
policy
|
|
1711
|
+
policy: opts.ssrfPolicy
|
|
1671
1712
|
});
|
|
1672
1713
|
}
|
|
1673
1714
|
async function assertSafeOutputPath(path2, allowedRoots) {
|