/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
ext/node/polyfills/internal/blocklist.mjs
430 строк
11 KB
Kenta Moriuchi
chore: make prefer-primordials lint an internal plugin (#35978)
23 июл 2026, 11:53
Не верифицирован
23 июл 2026, 11:53
5b55d08
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. // Copyright Joyent and Node contributors. All rights reserved. MIT license. (function () { const { core, primordials } = __bootstrap; const { op_blocklist_add_address, op_blocklist_add_range, op_blocklist_add_subnet, op_blocklist_check, op_blocklist_new, op_socket_address_get_serialization, op_socket_address_parse, } = core.ops; const { validateInt32, validateObject, validatePort, validateString, validateUint32, } = core.loadExtScript("ext:deno_node/internal/validators.mjs"); const { ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE, } = core.loadExtScript("ext:deno_node/internal/errors.ts"); const { customInspectSymbol, kEmptyObject } = core.loadExtScript( "ext:deno_node/internal/util.mjs", ); const { inspect } = core.loadExtScript( "ext:deno_node/internal/util/inspect.mjs", ); const { isIP, isIPv6 } = core.loadExtScript( "ext:deno_node/internal/net.ts", ); const { ArrayIsArray, ArrayPrototypeUnshift, JSONParse, NumberParseInt, ObjectDefineProperties, RegExpPrototypeExec, SafeArrayIterator, SafeRegExp, StringPrototypeEndsWith, StringPrototypeIncludes, StringPrototypeSlice, StringPrototypeStartsWith, StringPrototypeToLowerCase, Symbol, } = primordials; const kIPv4SubnetRe = new SafeRegExp( "Subnet: IPv4 (\\d{1,3}(?:\\.\\d{1,3}){3})\\/(\\d{1,2})", ); const kIPv4AddressRe = new SafeRegExp( "Address: IPv4 (\\d{1,3}(?:\\.\\d{1,3}){3})", ); const kIPv4RangeRe = new SafeRegExp( "Range: IPv4 (\\d{1,3}(?:\\.\\d{1,3}){3})-(\\d{1,3}(?:\\.\\d{1,3}){3})", ); const kIPv6SubnetRe = new SafeRegExp( "Subnet: IPv6 ([0-9a-fA-F:]{1,39})\\/([0-9]{1,3})", "i", ); const kIPv6AddressRe = new SafeRegExp( "Address: IPv6 ([0-9a-fA-F:]{1,39})", "i", ); const kIPv6RangeRe = new SafeRegExp( "Range: IPv6 ([0-9a-fA-F:]{1,39})-([0-9a-fA-F:]{1,39})", "i", ); const internalBlockList = Symbol("blocklist"); const kRules = Symbol("rules"); function formatFamily(family) { return family === "ipv6" ? "IPv6" : "IPv4"; } class BlockList { constructor() { this[internalBlockList] = op_blocklist_new(); this[kRules] = []; } static isBlockList(value) { return value?.[internalBlockList] !== undefined; } [customInspectSymbol](depth, options) { if (depth < 0) { return this; } const opts = { ...options, depth: options.depth == null ? null : options.depth - 1, }; return `BlockList ${ inspect({ rules: this[kRules], }, opts) }`; } addAddress(address, family = "ipv4") { if (!SocketAddress.isSocketAddress(address)) { validateString(address, "address"); validateString(family, "family"); new SocketAddress({ address, family, }); } else { family = address.family; address = address.address; } op_blocklist_add_address(this[internalBlockList], address); ArrayPrototypeUnshift( this[kRules], `Address: ${formatFamily(StringPrototypeToLowerCase(family))} ${address}`, ); } addRange(start, end, family = "ipv4") { if (!SocketAddress.isSocketAddress(start)) { validateString(start, "start"); validateString(family, "family"); new SocketAddress({ address: start, family, }); } else { family = start.family; start = start.address; } if (!SocketAddress.isSocketAddress(end)) { validateString(end, "end"); validateString(family, "family"); new SocketAddress({ address: end, family, }); } else { end = end.address; } const ret = op_blocklist_add_range(this[internalBlockList], start, end); if (ret === false) { throw new ERR_INVALID_ARG_VALUE("start", start, "must come before end"); } ArrayPrototypeUnshift( this[kRules], `Range: ${ formatFamily(StringPrototypeToLowerCase(family)) } ${start}-${end}`, ); } addSubnet(network, prefix, family = "ipv4") { if (!SocketAddress.isSocketAddress(network)) { validateString(network, "network"); validateString(family, "family"); new SocketAddress({ address: network, family, }); } else { family = network.family; network = network.address; } family = StringPrototypeToLowerCase(family); switch (family) { case "ipv4": validateInt32(prefix, "prefix", 0, 32); break; case "ipv6": validateInt32(prefix, "prefix", 0, 128); break; } op_blocklist_add_subnet(this[internalBlockList], network, prefix); ArrayPrototypeUnshift( this[kRules], `Subnet: ${formatFamily(family)} ${network}/${prefix}`, ); } check(address, family = "ipv4") { if (!SocketAddress.isSocketAddress(address)) { validateString(address, "address"); validateString(family, "family"); try { new SocketAddress({ address, family, }); } catch { // Ignore the error. If it's not a valid address, return false. return false; } } else { family = address.family; address = address.address; } try { return op_blocklist_check(this[internalBlockList], address, family); } catch (_) { // Node API expects false as return value if the address is invalid. // Example: `blocklist.check("1.1.1.1", "ipv6")` should return false. return false; } } get rules() { return this[kRules]; } toJSON() { return this[kRules]; } fromJSON(data) { if (ArrayIsArray(data)) { for (const n of new SafeArrayIterator(data)) { if (typeof n !== "string") { throw new ERR_INVALID_ARG_TYPE("data", ["string", "string[]"], data); } } } else if (typeof data !== "string") { throw new ERR_INVALID_ARG_TYPE("data", ["string", "string[]"], data); } else { data = JSONParse(data); if (!ArrayIsArray(data)) { throw new ERR_INVALID_ARG_TYPE("data", ["string", "string[]"], data); } for (const n of new SafeArrayIterator(data)) { if (typeof n !== "string") { throw new ERR_INVALID_ARG_TYPE("data", ["string", "string[]"], data); } } } parseIPInfo(this, data); } } function parseIPInfo(self, data) { for (const item of new SafeArrayIterator(data)) { if (StringPrototypeIncludes(item, "IPv4")) { const subnetMatch = RegExpPrototypeExec(kIPv4SubnetRe, item); if (subnetMatch) { self.addSubnet(subnetMatch[1], NumberParseInt(subnetMatch[2])); continue; } const addressMatch = RegExpPrototypeExec(kIPv4AddressRe, item); if (addressMatch) { self.addAddress(addressMatch[1]); continue; } const rangeMatch = RegExpPrototypeExec(kIPv4RangeRe, item); if (rangeMatch) { self.addRange(rangeMatch[1], rangeMatch[2]); continue; } } if (StringPrototypeIncludes(item, "IPv6")) { const ipv6SubnetMatch = RegExpPrototypeExec(kIPv6SubnetRe, item); if (ipv6SubnetMatch) { self.addSubnet( ipv6SubnetMatch[1], NumberParseInt(ipv6SubnetMatch[2]), "ipv6", ); continue; } const ipv6AddressMatch = RegExpPrototypeExec(kIPv6AddressRe, item); if (ipv6AddressMatch) { self.addAddress(ipv6AddressMatch[1], "ipv6"); continue; } const ipv6RangeMatch = RegExpPrototypeExec(kIPv6RangeRe, item); if (ipv6RangeMatch) { self.addRange(ipv6RangeMatch[1], ipv6RangeMatch[2], "ipv6"); continue; } } } } const kDetail = Symbol("kDetail"); class SocketAddress { static isSocketAddress(value) { if (value === null || typeof value !== "object") { return false; } if (value[kDetail] !== undefined) { return true; } // After a structured clone (e.g. postMessage), the symbol-keyed marker is // lost. Fall back to a duck-type check on the cloned data shape. return typeof value.address === "string" && typeof value.port === "number" && (value.family === "ipv4" || value.family === "ipv6") && typeof value.flowlabel === "number"; } static parse(input) { validateString(input, "input"); let url; try { url = new URL(`http://${input}`); } catch { return undefined; } const hostname = url.hostname; const portStr = url.port; const port = portStr === "" ? 0 : NumberParseInt(portStr, 10); if (isIP(hostname) === 4) { return new SocketAddress({ address: hostname, port }); } if ( StringPrototypeStartsWith(hostname, "[") && StringPrototypeEndsWith(hostname, "]") ) { const addr = StringPrototypeSlice(hostname, 1, -1); if (isIPv6(addr)) { return new SocketAddress({ address: addr, family: "ipv6", port }); } } return undefined; } constructor(options = kEmptyObject) { validateObject(options, "options"); let { family = "ipv4" } = options; const { address = (family === "ipv4" ? "127.0.0.1" : "::"), port = 0, flowlabel = 0, } = options; if (typeof family === "string") { // deno-lint-ignore deno-internal/prefer-primordials family = family.toLowerCase(); } switch (family) { case "ipv4": break; case "ipv6": break; default: throw new ERR_INVALID_ARG_VALUE("options.family", options.family); } validateString(address, "options.address"); validatePort(port, "options.port"); validateUint32(flowlabel, "options.flowlabel", false); let normalizedAddress = address; let normalizedFamily = family; const useInput = op_socket_address_parse( address, port, family, ); if (!useInput) { const { 0: address_, 1: family_ } = op_socket_address_get_serialization(); normalizedAddress = address_; normalizedFamily = family_; } this[kDetail] = { address: normalizedAddress, port, family: normalizedFamily, flowlabel, }; // Expose the data as own enumerable string-keyed properties so that the // instance survives structured clone (e.g. postMessage): symbol-keyed // properties are not preserved by HTML structured clone. ObjectDefineProperties(this, { address: { __proto__: null, value: normalizedAddress, enumerable: true, writable: false, configurable: false, }, port: { __proto__: null, value: port, enumerable: true, writable: false, configurable: false, }, family: { __proto__: null, value: normalizedFamily, enumerable: true, writable: false, configurable: false, }, flowlabel: { __proto__: null, value: flowlabel, enumerable: true, writable: false, configurable: false, }, }); } toJSON() { return { address: this.address, port: this.port, family: this.family, flowlabel: this.flowlabel, }; } } return { BlockList, SocketAddress, }; })();