diff --git a/THIRD-PARTY b/THIRD-PARTY index a6c0856..02ae882 100644 --- a/THIRD-PARTY +++ b/THIRD-PARTY @@ -2581,7 +2581,7 @@ Apache-2.0 The following npm package may be included in this product: - - ip-address@10.0.1 + - ip-address@10.2.0 This package contains the following license: diff --git a/dist/index.js b/dist/index.js index abaf387..991fb0a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -48956,6 +48956,23 @@ var require_util9 = __commonJS({ } }); +// node_modules/ip-address/dist/address-error.js +var require_address_error = __commonJS({ + "node_modules/ip-address/dist/address-error.js"(exports2) { + "use strict"; + Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.AddressError = void 0; + var AddressError = class extends Error { + constructor(message, parseMessage) { + super(message); + this.name = "AddressError"; + this.parseMessage = parseMessage; + } + }; + exports2.AddressError = AddressError; + } +}); + // node_modules/ip-address/dist/common.js var require_common2 = __commonJS({ "node_modules/ip-address/dist/common.js"(exports2) { @@ -48963,9 +48980,11 @@ var require_common2 = __commonJS({ Object.defineProperty(exports2, "__esModule", { value: true }); exports2.isInSubnet = isInSubnet; exports2.isCorrect = isCorrect; + exports2.prefixLengthFromMask = prefixLengthFromMask; exports2.numberToPaddedHex = numberToPaddedHex; exports2.stringToPaddedHex = stringToPaddedHex; exports2.testBit = testBit; + var address_error_1 = require_address_error(); function isInSubnet(address) { if (this.subnetMask < address.subnetMask) { return false; @@ -48986,6 +49005,20 @@ var require_common2 = __commonJS({ return this.parsedSubnet === String(this.subnetMask); }; } + function prefixLengthFromMask(value, totalBits) { + const binary = value.toString(2).padStart(totalBits, "0"); + if (binary.length > totalBits) { + throw new address_error_1.AddressError("Invalid subnet mask."); + } + const firstZero = binary.indexOf("0"); + if (firstZero === -1) { + return totalBits; + } + if (binary.slice(firstZero).includes("1")) { + throw new address_error_1.AddressError("Invalid subnet mask."); + } + return firstZero; + } function numberToPaddedHex(number) { return number.toString(16).padStart(2, "0"); } @@ -49016,23 +49049,6 @@ var require_constants7 = __commonJS({ } }); -// node_modules/ip-address/dist/address-error.js -var require_address_error = __commonJS({ - "node_modules/ip-address/dist/address-error.js"(exports2) { - "use strict"; - Object.defineProperty(exports2, "__esModule", { value: true }); - exports2.AddressError = void 0; - var AddressError = class extends Error { - constructor(message, parseMessage) { - super(message); - this.name = "AddressError"; - this.parseMessage = parseMessage; - } - }; - exports2.AddressError = AddressError; - } -}); - // node_modules/ip-address/dist/ipv4.js var require_ipv4 = __commonJS({ "node_modules/ip-address/dist/ipv4.js"(exports2) { @@ -49069,6 +49085,7 @@ var require_ipv4 = __commonJS({ var common = __importStar2(require_common2()); var constants = __importStar2(require_constants7()); var address_error_1 = require_address_error(); + var isCorrect4 = common.isCorrect(constants.BITS); var Address4 = class _Address4 { constructor(address) { this.groups = constants.GROUPS; @@ -49077,7 +49094,7 @@ var require_ipv4 = __commonJS({ this.subnet = "/32"; this.subnetMask = 32; this.v4 = true; - this.isCorrect = common.isCorrect(constants.BITS); + this.isCorrect = isCorrect4; this.isInSubnet = common.isInSubnet; this.address = address; const subnet = constants.RE_SUBNET_STRING.exec(address); @@ -49093,6 +49110,13 @@ var require_ipv4 = __commonJS({ this.addressMinusSuffix = address; this.parsedAddress = this.parse(address); } + /** + * Returns true if the given string is a valid IPv4 address (with optional + * CIDR subnet), false otherwise. Host bits in the subnet portion are + * allowed (e.g. `192.168.1.5/24` is valid); for strict network-address + * validation compare `correctForm()` to `startAddress().correctForm()`, + * or use `networkForm()`. + */ static isValid(address) { try { new _Address4(address); @@ -49101,8 +49125,11 @@ var require_ipv4 = __commonJS({ return false; } } - /* - * Parses a v4 address + /** + * Parses an IPv4 address string into its four octet groups and stores the + * result on `this.parsedAddress`. Called automatically by the constructor; + * you typically don't need to call it directly. Throws `AddressError` if + * the input is not a valid IPv4 address. */ parse(address) { const groups = address.split("."); @@ -49112,45 +49139,108 @@ var require_ipv4 = __commonJS({ return groups; } /** - * Returns the correct form of an address - * @memberof Address4 - * @instance - * @returns {String} + * Returns the address in correct form: octets joined with `.` and any + * leading zeros stripped (e.g. `192.168.1.1`). For IPv4 this matches the + * canonical dotted-decimal representation. */ correctForm() { return this.parsedAddress.map((part) => parseInt(part, 10)).join("."); } /** - * Converts a hex string to an IPv4 address object - * @memberof Address4 - * @static + * Construct an `Address4` from an address and a dotted-decimal subnet + * mask given as separate strings (e.g. as returned by Node's + * `os.networkInterfaces()`). Throws `AddressError` if the mask is + * non-contiguous (e.g. `255.0.255.0`). + * @example + * var address = Address4.fromAddressAndMask('192.168.1.1', '255.255.255.0'); + * address.subnetMask; // 24 + */ + static fromAddressAndMask(address, mask) { + const bits = common.prefixLengthFromMask(new _Address4(mask).bigInt(), constants.BITS); + return new _Address4(`${address}/${bits}`); + } + /** + * Construct an `Address4` from an address and a Cisco-style wildcard mask + * given as separate strings (e.g. `0.0.0.255` for a `/24`). The wildcard + * mask is the bitwise inverse of the subnet mask. Throws `AddressError` + * if the mask is non-contiguous (e.g. `0.255.0.255`). + * @example + * var address = Address4.fromAddressAndWildcardMask('10.0.0.1', '0.0.0.255'); + * address.subnetMask; // 24 + */ + static fromAddressAndWildcardMask(address, wildcardMask) { + const wildcard = new _Address4(wildcardMask).bigInt(); + const allOnes = (BigInt(1) << BigInt(constants.BITS)) - BigInt(1); + const mask = wildcard ^ allOnes; + const bits = common.prefixLengthFromMask(mask, constants.BITS); + return new _Address4(`${address}/${bits}`); + } + /** + * Construct an `Address4` from a wildcard pattern with trailing `*` + * octets. The number of trailing wildcards determines the prefix + * length: each `*` represents 8 bits. + * + * Only trailing whole-octet wildcards are supported. Partial-octet + * wildcards (e.g. `192.168.0.1*`) and interior wildcards (e.g. + * `192.*.0.1`) throw `AddressError`. + * @example + * Address4.fromWildcard('192.168.0.*').subnet; // '/24' + * Address4.fromWildcard('192.168.*.*').subnet; // '/16' + * Address4.fromWildcard('*.*.*.*').subnet; // '/0' + */ + static fromWildcard(input) { + const groups = input.split("."); + if (groups.length !== constants.GROUPS) { + throw new address_error_1.AddressError("Wildcard pattern must have 4 octets"); + } + let firstWildcard = -1; + for (let i5 = 0; i5 < groups.length; i5++) { + if (groups[i5] === "*") { + if (firstWildcard === -1) { + firstWildcard = i5; + } + } else if (firstWildcard !== -1) { + throw new address_error_1.AddressError("Wildcard `*` must only appear in trailing octets (e.g. `192.168.0.*`)"); + } + } + const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard; + const replaced = groups.map((g5) => g5 === "*" ? "0" : g5); + const subnetBits = constants.BITS - trailing * 8; + return new _Address4(`${replaced.join(".")}/${subnetBits}`); + } + /** + * Converts a hex string to an IPv4 address object. Accepts 8 hex digits + * with optional `:` separators (e.g. `'7f000001'` or `'7f:00:00:01'`). + * Throws `AddressError` for any other length or for non-hex characters. * @param {string} hex - a hex string to convert * @returns {Address4} */ static fromHex(hex) { - const padded = hex.replace(/:/g, "").padStart(8, "0"); + const stripped = hex.replace(/:/g, ""); + if (!/^[0-9a-fA-F]{8}$/.test(stripped)) { + throw new address_error_1.AddressError("IPv4 hex must be exactly 8 hex digits"); + } const groups = []; - let i5; - for (i5 = 0; i5 < 8; i5 += 2) { - const h5 = padded.slice(i5, i5 + 2); - groups.push(parseInt(h5, 16)); + for (let i5 = 0; i5 < 8; i5 += 2) { + groups.push(parseInt(stripped.slice(i5, i5 + 2), 16)); } return new _Address4(groups.join(".")); } /** - * Converts an integer into a IPv4 address object - * @memberof Address4 - * @static + * Converts an integer into a IPv4 address object. The integer must be a + * non-negative safe integer in the range `[0, 2**32 - 1]`; otherwise + * `AddressError` is thrown. * @param {integer} integer - a number to convert * @returns {Address4} */ static fromInteger(integer) { - return _Address4.fromHex(integer.toString(16)); + if (!Number.isInteger(integer) || integer < 0 || integer > 4294967295) { + throw new address_error_1.AddressError("IPv4 integer must be in the range 0 to 2**32 - 1"); + } + return _Address4.fromHex(integer.toString(16).padStart(8, "0")); } /** * Return an address from in-addr.arpa form - * @memberof Address4 - * @static * @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address * @returns {Adress4} * @example @@ -49164,17 +49254,15 @@ var require_ipv4 = __commonJS({ } /** * Converts an IPv4 address object to a hex string - * @memberof Address4 - * @instance * @returns {String} */ toHex() { return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(":"); } /** - * Converts an IPv4 address object to an array of bytes - * @memberof Address4 - * @instance + * Converts an IPv4 address object to an array of bytes. + * + * To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`. * @returns {Array} */ toArray() { @@ -49182,8 +49270,6 @@ var require_ipv4 = __commonJS({ } /** * Converts an IPv4 address object to an IPv6 address group - * @memberof Address4 - * @instance * @returns {String} */ toGroup6() { @@ -49196,8 +49282,6 @@ var require_ipv4 = __commonJS({ } /** * Returns the address as a `bigint` - * @memberof Address4 - * @instance * @returns {bigint} */ bigInt() { @@ -49205,8 +49289,6 @@ var require_ipv4 = __commonJS({ } /** * Helper function getting start address. - * @memberof Address4 - * @instance * @returns {bigint} */ _startAddress() { @@ -49215,8 +49297,6 @@ var require_ipv4 = __commonJS({ /** * The first address in the range given by this address' subnet. * Often referred to as the Network Address. - * @memberof Address4 - * @instance * @returns {Address4} */ startAddress() { @@ -49225,8 +49305,6 @@ var require_ipv4 = __commonJS({ /** * The first host address in the range given by this address's subnet ie * the first address after the Network Address - * @memberof Address4 - * @instance * @returns {Address4} */ startAddressExclusive() { @@ -49235,8 +49313,6 @@ var require_ipv4 = __commonJS({ } /** * Helper function getting end address. - * @memberof Address4 - * @instance * @returns {bigint} */ _endAddress() { @@ -49245,8 +49321,6 @@ var require_ipv4 = __commonJS({ /** * The last address in the range given by this address' subnet * Often referred to as the Broadcast - * @memberof Address4 - * @instance * @returns {Address4} */ endAddress() { @@ -49255,8 +49329,6 @@ var require_ipv4 = __commonJS({ /** * The last host address in the range given by this address's subnet ie * the last address prior to the Broadcast Address - * @memberof Address4 - * @instance * @returns {Address4} */ endAddressExclusive() { @@ -49264,20 +49336,76 @@ var require_ipv4 = __commonJS({ return _Address4.fromBigInt(this._endAddress() - adjust); } /** - * Converts a BigInt to a v4 address object - * @memberof Address4 - * @static + * The dotted-decimal form of the subnet mask, e.g. `255.255.240.0` for + * a `/20`. Returns an `Address4`; call `.correctForm()` for the string. + * @returns {Address4} + */ + subnetMaskAddress() { + return _Address4.fromBigInt(BigInt(`0b${"1".repeat(this.subnetMask)}${"0".repeat(constants.BITS - this.subnetMask)}`)); + } + /** + * The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is + * the bitwise inverse of `subnetMaskAddress()`. Returns an `Address4`; + * call `.correctForm()` for the string. + * @returns {Address4} + */ + wildcardMask() { + return _Address4.fromBigInt(BigInt(`0b${"0".repeat(this.subnetMask)}${"1".repeat(constants.BITS - this.subnetMask)}`)); + } + /** + * The network address in CIDR string form, e.g. `192.168.1.0/24` for + * `192.168.1.5/24`. For an address with no explicit subnet the prefix is + * `/32`, e.g. `networkForm()` on `192.168.1.5` returns `192.168.1.5/32`. + * @returns {string} + */ + networkForm() { + return `${this.startAddress().correctForm()}/${this.subnetMask}`; + } + /** + * Converts a BigInt to a v4 address object. The value must be in the + * range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown. * @param {bigint} bigInt - a BigInt to convert * @returns {Address4} */ static fromBigInt(bigInt) { - return _Address4.fromHex(bigInt.toString(16)); + if (bigInt < 0n || bigInt > 0xffffffffn) { + throw new address_error_1.AddressError("IPv4 BigInt must be in the range 0 to 2**32 - 1"); + } + return _Address4.fromHex(bigInt.toString(16).padStart(8, "0")); + } + /** + * Convert a byte array to an Address4 object. + * + * To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`. + * @param {Array} bytes - an array of 4 bytes (0-255) + * @returns {Address4} + */ + static fromByteArray(bytes) { + if (bytes.length !== 4) { + throw new address_error_1.AddressError("IPv4 addresses require exactly 4 bytes"); + } + for (let i5 = 0; i5 < bytes.length; i5++) { + if (!Number.isInteger(bytes[i5]) || bytes[i5] < 0 || bytes[i5] > 255) { + throw new address_error_1.AddressError("All bytes must be integers between 0 and 255"); + } + } + return this.fromUnsignedByteArray(bytes); + } + /** + * Convert an unsigned byte array to an Address4 object + * @param {Array} bytes - an array of 4 unsigned bytes (0-255) + * @returns {Address4} + */ + static fromUnsignedByteArray(bytes) { + if (bytes.length !== 4) { + throw new address_error_1.AddressError("IPv4 addresses require exactly 4 bytes"); + } + const address = bytes.join("."); + return new _Address4(address); } /** * Returns the first n bits of the address, defaulting to the * subnet mask - * @memberof Address4 - * @instance * @returns {String} */ mask(mask) { @@ -49288,8 +49416,6 @@ var require_ipv4 = __commonJS({ } /** * Returns the bits in the given range as a base-2 string - * @memberof Address4 - * @instance * @returns {string} */ getBitsBase2(start, end) { @@ -49297,10 +49423,8 @@ var require_ipv4 = __commonJS({ } /** * Return the reversed ip6.arpa form of the address - * @memberof Address4 * @param {Object} options * @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix - * @instance * @returns {String} */ reverseForm(options) { @@ -49315,21 +49439,62 @@ var require_ipv4 = __commonJS({ } /** * Returns true if the given address is a multicast address - * @memberof Address4 - * @instance * @returns {boolean} */ isMulticast() { - return this.isInSubnet(new _Address4("224.0.0.0/4")); + return this.isInSubnet(MULTICAST_V4); + } + /** + * Returns true if the address is in one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private address ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`). + * @returns {boolean} + */ + isPrivate() { + return PRIVATE_V4.some((subnet) => this.isInSubnet(subnet)); + } + /** + * Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)). + * @returns {boolean} + */ + isLoopback() { + return this.isInSubnet(LOOPBACK_V4); + } + /** + * Returns true if the address is in the link-local range `169.254.0.0/16` ([RFC 3927](https://datatracker.ietf.org/doc/html/rfc3927)). + * @returns {boolean} + */ + isLinkLocal() { + return this.isInSubnet(LINK_LOCAL_V4); + } + /** + * Returns true if the address is the unspecified address `0.0.0.0`. + * @returns {boolean} + */ + isUnspecified() { + return this.isInSubnet(UNSPECIFIED_V4); + } + /** + * Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)). + * @returns {boolean} + */ + isBroadcast() { + return this.isInSubnet(BROADCAST_V4); + } + /** + * Returns true if the address is in the carrier-grade NAT range `100.64.0.0/10` ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)). + * @returns {boolean} + */ + isCGNAT() { + return this.isInSubnet(CGNAT_V4); } /** * Returns a zero-padded base-2 string representation of the address - * @memberof Address4 - * @instance * @returns {string} */ binaryZeroPad() { - return this.bigInt().toString(2).padStart(constants.BITS, "0"); + if (this._binaryZeroPad === void 0) { + this._binaryZeroPad = this.bigInt().toString(2).padStart(constants.BITS, "0"); + } + return this._binaryZeroPad; } /** * Groups an IPv4 address for inclusion at the end of an IPv6 address @@ -49341,6 +49506,17 @@ var require_ipv4 = __commonJS({ } }; exports2.Address4 = Address4; + var MULTICAST_V4 = new Address4("224.0.0.0/4"); + var PRIVATE_V4 = [ + new Address4("10.0.0.0/8"), + new Address4("172.16.0.0/12"), + new Address4("192.168.0.0/16") + ]; + var LOOPBACK_V4 = new Address4("127.0.0.0/8"); + var LINK_LOCAL_V4 = new Address4("169.254.0.0/16"); + var UNSPECIFIED_V4 = new Address4("0.0.0.0/32"); + var BROADCAST_V4 = new Address4("255.255.255.255/32"); + var CGNAT_V4 = new Address4("100.64.0.0/10"); } }); @@ -49384,7 +49560,12 @@ var require_constants8 = __commonJS({ "::/128": "Unspecified", "::1/128": "Loopback", "ff00::/8": "Multicast", - "fe80::/10": "Link-local unicast" + "fe80::/10": "Link-local unicast", + "fc00::/7": "Unique local", + "2002::/16": "6to4", + "2001:db8::/32": "Documentation", + "64:ff9b::/96": "NAT64 (well-known)", + "64:ff9b:1::/48": "NAT64 (local-use)" }; exports2.RE_BAD_CHARACTERS = /([^0-9a-f:/%])/gi; exports2.RE_BAD_ADDRESS = /([0-9a-f]{5,}|:{3,}|[^:]:$|^:[^:]|\/$)/gi; @@ -49400,19 +49581,23 @@ var require_helpers = __commonJS({ "node_modules/ip-address/dist/v6/helpers.js"(exports2) { "use strict"; Object.defineProperty(exports2, "__esModule", { value: true }); + exports2.escapeHtml = escapeHtml; exports2.spanAllZeroes = spanAllZeroes; exports2.spanAll = spanAll; exports2.spanLeadingZeroes = spanLeadingZeroes; exports2.simpleGroup = simpleGroup; + function escapeHtml(s) { + return s.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """).replace(/'/g, "'"); + } function spanAllZeroes(s) { - return s.replace(/(0+)/g, '$1'); + return escapeHtml(s).replace(/(0+)/g, '$1'); } function spanAll(s, offset = 0) { const letters = s.split(""); - return letters.map((n3, i5) => `${spanAllZeroes(n3)}`).join(""); + return letters.map((n3, i5) => `${spanAllZeroes(n3)}`).join(""); } function spanLeadingZeroesSimple(group) { - return group.replace(/^(0+)/, '$1'); + return escapeHtml(group).replace(/^(0+)/, '$1'); } function spanLeadingZeroes(address) { const groups = address.split(":"); @@ -49563,6 +49748,7 @@ var require_ipv6 = __commonJS({ var regular_expressions_1 = require_regular_expressions(); var address_error_1 = require_address_error(); var common_1 = require_common2(); + var isCorrect6 = common.isCorrect(constants6.BITS); function assert4(condition) { if (!condition) { throw new Error("Assertion failed."); @@ -49608,7 +49794,7 @@ var require_ipv6 = __commonJS({ this.v4 = false; this.zone = ""; this.isInSubnet = common.isInSubnet; - this.isCorrect = common.isCorrect(constants6.BITS); + this.isCorrect = isCorrect6; if (optionalGroups === void 0) { this.groups = constants6.GROUPS; } else { @@ -49635,6 +49821,13 @@ var require_ipv6 = __commonJS({ this.addressMinusSuffix = address; this.parsedAddress = this.parse(this.addressMinusSuffix); } + /** + * Returns true if the given string is a valid IPv6 address (with optional + * CIDR subnet and zone identifier), false otherwise. Host bits in the + * subnet portion are allowed (e.g. `2001:db8::1/32` is valid); for strict + * network-address validation compare `correctForm()` to + * `startAddress().correctForm()`, or use `networkForm()`. + */ static isValid(address) { try { new _Address6(address); @@ -49644,9 +49837,8 @@ var require_ipv6 = __commonJS({ } } /** - * Convert a BigInt to a v6 address object - * @memberof Address6 - * @static + * Convert a BigInt to a v6 address object. The value must be in the + * range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown. * @param {bigint} bigInt - a BigInt to convert * @returns {Address6} * @example @@ -49655,19 +49847,21 @@ var require_ipv6 = __commonJS({ * address.correctForm(); // '::e8:d4a5:1000' */ static fromBigInt(bigInt) { + if (bigInt < 0n || bigInt > (1n << BigInt(constants6.BITS)) - 1n) { + throw new address_error_1.AddressError("IPv6 BigInt must be in the range 0 to 2**128 - 1"); + } const hex = bigInt.toString(16).padStart(32, "0"); const groups = []; - let i5; - for (i5 = 0; i5 < constants6.GROUPS; i5++) { + for (let i5 = 0; i5 < constants6.GROUPS; i5++) { groups.push(hex.slice(i5 * 4, (i5 + 1) * 4)); } return new _Address6(groups.join(":")); } /** - * Convert a URL (with optional port number) to an address object - * @memberof Address6 - * @static - * @param {string} url - a URL with optional port number + * Parse a URL (with optional bracketed host and port) into an address and + * port. Returns either `{ address, port }` on success or + * `{ error, address: null, port: null }` if the URL could not be parsed. + * Ports are returned as numbers (or `null` if absent or out of range). * @example * var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/'); * addressAndPort.address.correctForm(); // 'ffff::' @@ -49715,10 +49909,89 @@ var require_ipv6 = __commonJS({ port }; } + /** + * Construct an `Address6` from an address and a hex subnet mask given as + * separate strings (e.g. as returned by Node's `os.networkInterfaces()`). + * Throws `AddressError` if the mask is non-contiguous (e.g. + * `ffff::ffff`). + * @example + * var address = Address6.fromAddressAndMask('fe80::1', 'ffff:ffff:ffff:ffff::'); + * address.subnetMask; // 64 + */ + static fromAddressAndMask(address, mask) { + const bits = common.prefixLengthFromMask(new _Address6(mask).bigInt(), constants6.BITS); + return new _Address6(`${address}/${bits}`); + } + /** + * Construct an `Address6` from an address and a Cisco-style wildcard mask + * given as separate strings (e.g. `::ffff:ffff:ffff:ffff` for a `/64`). + * The wildcard mask is the bitwise inverse of the subnet mask. Throws + * `AddressError` if the mask is non-contiguous. + * @example + * var address = Address6.fromAddressAndWildcardMask('fe80::1', '::ffff:ffff:ffff:ffff'); + * address.subnetMask; // 64 + */ + static fromAddressAndWildcardMask(address, wildcardMask) { + const wildcard = new _Address6(wildcardMask).bigInt(); + const allOnes = (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1); + const mask = wildcard ^ allOnes; + const bits = common.prefixLengthFromMask(mask, constants6.BITS); + return new _Address6(`${address}/${bits}`); + } + /** + * Construct an `Address6` from a wildcard pattern with trailing `*` + * groups. The number of trailing wildcards determines the prefix + * length: each `*` represents 16 bits. `::` is expanded to zero groups + * (not wildcards) before evaluating trailing wildcards. + * + * Only trailing whole-group wildcards are supported. Partial-group + * wildcards (e.g. `2001:db8::0*`) and interior wildcards (e.g. + * `*::1`) throw `AddressError`. + * @example + * Address6.fromWildcard('2001:db8:*:*:*:*:*:*').subnet; // '/32' + * Address6.fromWildcard('2001:db8::*').subnet; // '/112' + * Address6.fromWildcard('*:*:*:*:*:*:*:*').subnet; // '/0' + */ + static fromWildcard(input) { + if (input.includes("%") || input.includes("/")) { + throw new address_error_1.AddressError("Wildcard pattern must not include a zone or CIDR suffix"); + } + const halves = input.split("::"); + if (halves.length > 2) { + throw new address_error_1.AddressError("Wildcard pattern cannot contain more than one '::'"); + } + let groups; + if (halves.length === 2) { + const left = halves[0] === "" ? [] : halves[0].split(":"); + const right = halves[1] === "" ? [] : halves[1].split(":"); + const remaining = constants6.GROUPS - left.length - right.length; + if (remaining < 1) { + throw new address_error_1.AddressError("Wildcard pattern with '::' has too many groups"); + } + groups = [...left, ...new Array(remaining).fill("0"), ...right]; + } else { + groups = input.split(":"); + } + if (groups.length !== constants6.GROUPS) { + throw new address_error_1.AddressError("Wildcard pattern must have 8 groups"); + } + let firstWildcard = -1; + for (let i5 = 0; i5 < groups.length; i5++) { + if (groups[i5] === "*") { + if (firstWildcard === -1) { + firstWildcard = i5; + } + } else if (firstWildcard !== -1) { + throw new address_error_1.AddressError("Wildcard `*` must only appear in trailing groups (e.g. `2001:db8:*:*:*:*:*:*`)"); + } + } + const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard; + const replaced = groups.map((g5) => g5 === "*" ? "0" : g5); + const subnetBits = constants6.BITS - trailing * 16; + return new _Address6(`${replaced.join(":")}/${subnetBits}`); + } /** * Create an IPv6-mapped address given an IPv4 address - * @memberof Address6 - * @static * @param {string} address - An IPv4 address string * @returns {Address6} * @example @@ -49733,8 +50006,6 @@ var require_ipv6 = __commonJS({ } /** * Return an address from ip6.arpa form - * @memberof Address6 - * @static * @param {string} arpaFormAddress - an 'ip6.arpa' form address * @returns {Adress6} * @example @@ -49757,8 +50028,6 @@ var require_ipv6 = __commonJS({ } /** * Return the Microsoft UNC transcription of the address - * @memberof Address6 - * @instance * @returns {String} the Microsoft UNC transcription of the address */ microsoftTranscription() { @@ -49766,8 +50035,6 @@ var require_ipv6 = __commonJS({ } /** * Return the first n bits of the address, defaulting to the subnet mask - * @memberof Address6 - * @instance * @param {number} [mask=subnet] - the number of bits to mask * @returns {String} the first n bits of the address as a string */ @@ -49776,8 +50043,6 @@ var require_ipv6 = __commonJS({ } /** * Return the number of possible subnets of a given size in the address - * @memberof Address6 - * @instance * @param {number} [subnetSize=128] - the subnet size * @returns {String} */ @@ -49793,8 +50058,6 @@ var require_ipv6 = __commonJS({ } /** * Helper function getting start address. - * @memberof Address6 - * @instance * @returns {bigint} */ _startAddress() { @@ -49803,8 +50066,6 @@ var require_ipv6 = __commonJS({ /** * The first address in the range given by this address' subnet * Often referred to as the Network Address. - * @memberof Address6 - * @instance * @returns {Address6} */ startAddress() { @@ -49813,8 +50074,6 @@ var require_ipv6 = __commonJS({ /** * The first host address in the range given by this address's subnet ie * the first address after the Network Address - * @memberof Address6 - * @instance * @returns {Address6} */ startAddressExclusive() { @@ -49823,8 +50082,6 @@ var require_ipv6 = __commonJS({ } /** * Helper function getting end address. - * @memberof Address6 - * @instance * @returns {bigint} */ _endAddress() { @@ -49833,8 +50090,6 @@ var require_ipv6 = __commonJS({ /** * The last address in the range given by this address' subnet * Often referred to as the Broadcast - * @memberof Address6 - * @instance * @returns {Address6} */ endAddress() { @@ -49843,8 +50098,6 @@ var require_ipv6 = __commonJS({ /** * The last host address in the range given by this address's subnet ie * the last address prior to the Broadcast Address - * @memberof Address6 - * @instance * @returns {Address6} */ endAddressExclusive() { @@ -49852,36 +50105,69 @@ var require_ipv6 = __commonJS({ return _Address6.fromBigInt(this._endAddress() - adjust); } /** - * Return the scope of the address - * @memberof Address6 - * @instance + * The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a + * `/64`. Returns an `Address6`; call `.correctForm()` for the string. + * @returns {Address6} + */ + subnetMaskAddress() { + return _Address6.fromBigInt(BigInt(`0b${"1".repeat(this.subnetMask)}${"0".repeat(constants6.BITS - this.subnetMask)}`)); + } + /** + * The Cisco-style wildcard mask, e.g. `::ffff:ffff:ffff:ffff` for a + * `/64`. This is the bitwise inverse of `subnetMaskAddress()`. Returns + * an `Address6`; call `.correctForm()` for the string. + * @returns {Address6} + */ + wildcardMask() { + return _Address6.fromBigInt(BigInt(`0b${"0".repeat(this.subnetMask)}${"1".repeat(constants6.BITS - this.subnetMask)}`)); + } + /** + * The network address in CIDR string form, e.g. `2001:db8::/32` for + * `2001:db8::1/32`. For an address with no explicit subnet the prefix + * is `/128`, e.g. `networkForm()` on `2001:db8::1` returns + * `2001:db8::1/128`. + * @returns {string} + */ + networkForm() { + return `${this.startAddress().correctForm()}/${this.subnetMask}`; + } + /** + * Return the scope of the address. The 4-bit scope field + * ([RFC 4291 §2.7](https://datatracker.ietf.org/doc/html/rfc4291#section-2.7)) + * is only defined for multicast addresses; for unicast addresses the scope + * is derived from the address type per + * [RFC 4007 §6](https://datatracker.ietf.org/doc/html/rfc4007#section-6). * @returns {String} */ getScope() { - let scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)]; - if (this.getType() === "Global unicast" && scope !== "Link local") { - scope = "Global"; + const type = this.getType(); + if (type === "Multicast" || type.startsWith("Multicast ")) { + const scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)]; + return scope || "Unknown"; } - return scope || "Unknown"; + if (type === "Link-local unicast" || type === "Loopback") { + return "Link local"; + } + if (type === "Unspecified") { + return "Unknown"; + } + return "Global"; } /** * Return the type of the address - * @memberof Address6 - * @instance * @returns {String} */ getType() { - for (const subnet of Object.keys(constants6.TYPES)) { - if (this.isInSubnet(new _Address6(subnet))) { - return constants6.TYPES[subnet]; + for (let i5 = 0; i5 < TYPE_SUBNETS.length; i5++) { + const entry = TYPE_SUBNETS[i5]; + if (this.isInSubnet(entry[0])) { + return entry[1]; } } return "Global unicast"; } /** * Return the bits in the given range as a BigInt - * @memberof Address6 - * @instance * @returns {bigint} */ getBits(start, end) { @@ -49889,8 +50175,6 @@ var require_ipv6 = __commonJS({ } /** * Return the bits in the given range as a base-2 string - * @memberof Address6 - * @instance * @returns {String} */ getBitsBase2(start, end) { @@ -49898,8 +50182,6 @@ var require_ipv6 = __commonJS({ } /** * Return the bits in the given range as a base-16 string - * @memberof Address6 - * @instance * @returns {String} */ getBitsBase16(start, end) { @@ -49911,8 +50193,6 @@ var require_ipv6 = __commonJS({ } /** * Return the bits that are set past the subnet mask length - * @memberof Address6 - * @instance * @returns {String} */ getBitsPastSubnet() { @@ -49920,10 +50200,8 @@ var require_ipv6 = __commonJS({ } /** * Return the reversed ip6.arpa form of the address - * @memberof Address6 * @param {Object} options * @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix - * @instance * @returns {String} */ reverseForm(options) { @@ -49944,10 +50222,10 @@ var require_ipv6 = __commonJS({ return "ip6.arpa."; } /** - * Return the correct form of the address - * @memberof Address6 - * @instance - * @returns {String} + * Returns the address in correct form, per + * [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros + * stripped, the longest run of zero groups collapsed to `::`, and hex digits + * lowercased (e.g. `2001:db8::1`). This is the recommended form for display. */ correctForm() { let i5; @@ -49989,8 +50267,6 @@ var require_ipv6 = __commonJS({ } /** * Return a zero-padded base-2 string representation of the address - * @memberof Address6 - * @instance * @returns {String} * @example * var address = new Address6('2001:4860:4001:803::1011'); @@ -49999,10 +50275,22 @@ var require_ipv6 = __commonJS({ * // 0000000000000000000000000000000000000000000000000001000000010001' */ binaryZeroPad() { - return this.bigInt().toString(2).padStart(constants6.BITS, "0"); + if (this._binaryZeroPad === void 0) { + this._binaryZeroPad = this.bigInt().toString(2).padStart(constants6.BITS, "0"); + } + return this._binaryZeroPad; } + /** + * Parses a v4-in-v6 string (e.g. `::ffff:192.168.0.1`) by extracting the + * trailing IPv4 address into `this.address4` / `this.parsedAddress4` and + * returning the address with the v4 portion converted to two v6 groups. + * Used internally by `parse()`. + */ // TODO: Improve the semantics of this helper function parse4in6(address) { + if (address.indexOf(".") === -1) { + return address; + } const groups = address.split(":"); const lastGroup = groups.slice(-1)[0]; const address4 = lastGroup.match(constants4.RE_ADDRESS); @@ -50011,7 +50299,10 @@ var require_ipv6 = __commonJS({ this.address4 = new ipv4_1.Address4(this.parsedAddress4); for (let i5 = 0; i5 < this.address4.groups; i5++) { if (/^0[0-9]+/.test(this.address4.parsedAddress[i5])) { - throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", address.replace(constants4.RE_ADDRESS, this.address4.parsedAddress.map(spanLeadingZeroes4).join("."))); + const highlighted = this.address4.parsedAddress.map(spanLeadingZeroes4).join("."); + const prefix = groups.slice(0, -1).map(helpers.escapeHtml).join(":"); + const separator = groups.length > 1 ? ":" : ""; + throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", `${prefix}${separator}${highlighted}`); } } this.v4 = true; @@ -50020,6 +50311,13 @@ var require_ipv6 = __commonJS({ } return address; } + /** + * Parses an IPv6 address string into its 8 hexadecimal groups (expanding + * any `::` elision and any trailing v4-in-v6 portion) and stores the result + * on `this.parsedAddress`. Called automatically by the constructor; you + * typically don't need to call it directly. Throws `AddressError` if the + * input is malformed. + */ // TODO: Make private? parse(address) { address = this.parse4in6(address); @@ -50067,18 +50365,16 @@ var require_ipv6 = __commonJS({ return groups; } /** - * Return the canonical form of the address - * @memberof Address6 - * @instance - * @returns {String} + * Returns the canonical (fully expanded) form of the address: all 8 groups, + * each padded to 4 hex digits, with no `::` collapsing + * (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and + * byte-exact comparison. */ canonicalForm() { return this.parsedAddress.map(paddedHex).join(":"); } /** * Return the decimal form of the address - * @memberof Address6 - * @instance * @returns {String} */ decimal() { @@ -50086,8 +50382,6 @@ var require_ipv6 = __commonJS({ } /** * Return the address as a BigInt - * @memberof Address6 - * @instance * @returns {bigint} */ bigInt() { @@ -50095,8 +50389,6 @@ var require_ipv6 = __commonJS({ } /** * Return the last two groups of this address as an IPv4 address string - * @memberof Address6 - * @instance * @returns {Address4} * @example * var address = new Address6('2001:4860:4001::1825:bf11'); @@ -50104,12 +50396,10 @@ var require_ipv6 = __commonJS({ */ to4() { const binary = this.binaryZeroPad().split(""); - return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join("")}`).toString(16)); + return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join("")}`).toString(16).padStart(8, "0")); } /** * Return the v4-in-v6 form of the address - * @memberof Address6 - * @instance * @returns {String} */ to4in6() { @@ -50123,10 +50413,10 @@ var require_ipv6 = __commonJS({ return correct + infix + address4.address; } /** - * Return an object containing the Teredo properties of the address - * @memberof Address6 - * @instance - * @returns {Object} + * Decodes the Teredo tunneling fields embedded in this address. Returns the + * Teredo prefix, server IPv4, client IPv4, raw flag bits, cone-NAT flag, + * UDP port, and Microsoft-format flag breakdown (reserved, universal/local, + * group/individual, nonce). Only meaningful for addresses in `2001::/32`. */ inspectTeredo() { const prefix = this.getBitsBase16(0, 32); @@ -50134,7 +50424,7 @@ var require_ipv6 = __commonJS({ const udpPort = (bitsForUdpPort ^ BigInt("0xffff")).toString(); const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64)); const bitsForClient4 = this.getBits(96, 128); - const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt("0xffffffff")).toString(16)); + const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt("0xffffffff")).toString(16).padStart(8, "0")); const flagsBase2 = this.getBitsBase2(64, 80); const coneNat = (0, common_1.testBit)(flagsBase2, 15); const reserved = (0, common_1.testBit)(flagsBase2, 14); @@ -50157,10 +50447,9 @@ var require_ipv6 = __commonJS({ }; } /** - * Return an object containing the 6to4 properties of the address - * @memberof Address6 - * @instance - * @returns {Object} + * Decodes the 6to4 tunneling fields embedded in this address. Returns the + * 6to4 prefix and the embedded IPv4 gateway address. Only meaningful for + * addresses in `2002::/16`. */ inspect6to4() { const prefix = this.getBitsBase16(0, 16); @@ -50172,8 +50461,6 @@ var require_ipv6 = __commonJS({ } /** * Return a v6 6to4 address from a v6 v4inv6 address - * @memberof Address6 - * @instance * @returns {Address6} */ to6to4() { @@ -50190,9 +50477,73 @@ var require_ipv6 = __commonJS({ return new _Address6(addr6to4); } /** - * Return a byte array - * @memberof Address6 - * @instance + * Embed an IPv4 address into a NAT64 IPv6 address using the encoding + * defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052). + * The default prefix is the well-known prefix `64:ff9b::/96`. The prefix + * length must be one of 32, 40, 48, 56, 64, or 96; for prefixes shorter + * than /64 the IPv4 octets are split around the reserved bits 64–71. + * @example + * Address6.fromAddress4Nat64('192.0.2.33').correctForm(); // '64:ff9b::c000:221' + * Address6.fromAddress4Nat64('192.0.2.33', '2001:db8::/32').correctForm(); // '2001:db8:c000:221::' + */ + static fromAddress4Nat64(address, prefix = "64:ff9b::/96") { + const v4 = new ipv4_1.Address4(address); + const prefix6 = new _Address6(prefix); + const pl = prefix6.subnetMask; + if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) { + throw new address_error_1.AddressError("NAT64 prefix length must be 32, 40, 48, 56, 64, or 96"); + } + const prefixBits = prefix6.binaryZeroPad(); + const v4Bits = v4.binaryZeroPad(); + let bits; + if (pl === 96) { + bits = prefixBits.slice(0, 96) + v4Bits; + } else { + const beforeU = 64 - pl; + bits = prefixBits.slice(0, pl) + v4Bits.slice(0, beforeU) + "00000000" + v4Bits.slice(beforeU) + "0".repeat(128 - 72 - (32 - beforeU)); + } + const hex = BigInt(`0b${bits}`).toString(16).padStart(32, "0"); + const groups = []; + for (let i5 = 0; i5 < 8; i5++) { + groups.push(hex.slice(i5 * 4, (i5 + 1) * 4)); + } + return new _Address6(groups.join(":")); + } + /** + * Extract the embedded IPv4 address from a NAT64 IPv6 address using the + * encoding defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052). + * The default prefix is the well-known prefix `64:ff9b::/96`. Returns + * `null` if this address is not contained within the given prefix. + * @example + * new Address6('64:ff9b::c000:221').toAddress4Nat64()!.correctForm(); // '192.0.2.33' + */ + toAddress4Nat64(prefix = "64:ff9b::/96") { + const prefix6 = new _Address6(prefix); + const pl = prefix6.subnetMask; + if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) { + throw new address_error_1.AddressError("NAT64 prefix length must be 32, 40, 48, 56, 64, or 96"); + } + if (!this.isInSubnet(prefix6)) { + return null; + } + const bits = this.binaryZeroPad(); + let v4Bits; + if (pl === 96) { + v4Bits = bits.slice(96, 128); + } else { + const beforeU = 64 - pl; + v4Bits = bits.slice(pl, pl + beforeU) + bits.slice(72, 72 + (32 - beforeU)); + } + const octets = []; + for (let i5 = 0; i5 < 4; i5++) { + octets.push(parseInt(v4Bits.slice(i5 * 8, (i5 + 1) * 8), 2).toString()); + } + return new ipv4_1.Address4(octets.join(".")); + } + /** + * Return a byte array. + * + * To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`. * @returns {Array} */ toByteArray() { @@ -50206,27 +50557,27 @@ var require_ipv6 = __commonJS({ return bytes; } /** - * Return an unsigned byte array - * @memberof Address6 - * @instance + * Return an unsigned byte array. + * + * To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`. * @returns {Array} */ toUnsignedByteArray() { return this.toByteArray().map(unsignByte); } /** - * Convert a byte array to an Address6 object - * @memberof Address6 - * @static + * Convert a byte array to an Address6 object. + * + * To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`. * @returns {Address6} */ static fromByteArray(bytes) { return this.fromUnsignedByteArray(bytes.map(unsignByte)); } /** - * Convert an unsigned byte array to an Address6 object - * @memberof Address6 - * @static + * Convert an unsigned byte array to an Address6 object. + * + * To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`. * @returns {Address6} */ static fromUnsignedByteArray(bytes) { @@ -50241,8 +50592,6 @@ var require_ipv6 = __commonJS({ } /** * Returns true if the address is in the canonical form, false otherwise - * @memberof Address6 - * @instance * @returns {boolean} */ isCanonical() { @@ -50250,8 +50599,6 @@ var require_ipv6 = __commonJS({ } /** * Returns true if the address is a link local address, false otherwise - * @memberof Address6 - * @instance * @returns {boolean} */ isLinkLocal() { @@ -50262,53 +50609,81 @@ var require_ipv6 = __commonJS({ } /** * Returns true if the address is a multicast address, false otherwise - * @memberof Address6 - * @instance * @returns {boolean} */ isMulticast() { - return this.getType() === "Multicast"; + const type = this.getType(); + return type === "Multicast" || type.startsWith("Multicast "); } /** - * Returns true if the address is a v4-in-v6 address, false otherwise - * @memberof Address6 - * @instance + * Returns true if the address was written in v4-in-v6 dotted-quad notation + * (e.g. `::ffff:127.0.0.1`), false otherwise. This is a notation-level flag + * and does not reflect whether the address bits lie in the IPv4-mapped + * (`::ffff:0:0/96`) subnet — for that, see {@link isMapped4}. * @returns {boolean} */ is4() { return this.v4; } + /** + * Returns true if the address is an IPv4-mapped IPv6 address in + * `::ffff:0:0/96` ([RFC 4291 §2.5.5.2](https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2)), + * false otherwise. Unlike {@link is4}, this checks the underlying address + * bits rather than the textual notation, so `::ffff:127.0.0.1` and + * `::ffff:7f00:1` both return true. + * @returns {boolean} + */ + isMapped4() { + return this.isInSubnet(IPV4_MAPPED_SUBNET); + } /** * Returns true if the address is a Teredo address, false otherwise - * @memberof Address6 - * @instance * @returns {boolean} */ isTeredo() { - return this.isInSubnet(new _Address6("2001::/32")); + return this.isInSubnet(TEREDO_SUBNET); } /** * Returns true if the address is a 6to4 address, false otherwise - * @memberof Address6 - * @instance * @returns {boolean} */ is6to4() { - return this.isInSubnet(new _Address6("2002::/16")); + return this.isInSubnet(SIX_TO_FOUR_SUBNET); } /** * Returns true if the address is a loopback address, false otherwise - * @memberof Address6 - * @instance * @returns {boolean} */ isLoopback() { return this.getType() === "Loopback"; } + /** + * Returns true if the address is a Unique Local Address in `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)). ULAs are the IPv6 equivalent of IPv4 [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private addresses. + * @returns {boolean} + */ + isULA() { + return this.isInSubnet(ULA_SUBNET); + } + /** + * Returns true if the address is the unspecified address `::`. + * @returns {boolean} + */ + isUnspecified() { + return this.getType() === "Unspecified"; + } + /** + * Returns true if the address is in the documentation prefix `2001:db8::/32` ([RFC 3849](https://datatracker.ietf.org/doc/html/rfc3849)). + * @returns {boolean} + */ + isDocumentation() { + return this.isInSubnet(DOCUMENTATION_SUBNET); + } // #endregion // #region HTML /** - * @returns {String} the address in link form with a default port of 80 + * Returns the address as an HTTP URL with the host bracketed, e.g. + * `http://[2001:db8::1]/`. If `optionalPort` is provided it is appended, + * e.g. `http://[2001:db8::1]:8080/`. */ href(optionalPort) { if (optionalPort === void 0) { @@ -50319,7 +50694,12 @@ var require_ipv6 = __commonJS({ return `http://[${this.correctForm()}]${optionalPort}/`; } /** - * @returns {String} a link suitable for conveying the address via a URL hash + * Returns an HTML `` element whose `href` encodes the address in a URL + * hash fragment (default prefix `/#address=`). Useful for linking between + * pages of an address-inspector UI. + * @param options.className - CSS class for the rendered `` element + * @param options.prefix - hash prefix prepended to the address (default `/#address=`) + * @param options.v4 - when true, render the address in v4-in-v6 form */ link(options) { if (!options) { @@ -50339,10 +50719,13 @@ var require_ipv6 = __commonJS({ formFunction = this.to4in6; } const form = formFunction.call(this); + const safeHref = helpers.escapeHtml(`${options.prefix}${form}`); + const safeForm = helpers.escapeHtml(form); if (options.className) { - return `${form}`; + const safeClass = helpers.escapeHtml(options.className); + return `${safeForm}`; } - return `${form}`; + return `${safeForm}`; } /** * Groups an address @@ -50350,12 +50733,12 @@ var require_ipv6 = __commonJS({ */ group() { if (this.elidedGroups === 0) { - return helpers.simpleGroup(this.address).join(":"); + return helpers.simpleGroup(this.addressMinusSuffix).join(":"); } assert4(typeof this.elidedGroups === "number"); assert4(typeof this.elisionBegin === "number"); const output = []; - const [left, right] = this.address.split("::"); + const [left, right] = this.addressMinusSuffix.split("::"); if (left.length) { output.push(...helpers.simpleGroup(left)); } else { @@ -50383,8 +50766,6 @@ var require_ipv6 = __commonJS({ /** * Generate a regular expression string that can be used to find or validate * all variations of this address - * @memberof Address6 - * @instance * @param {boolean} substringSearch * @returns {string} */ @@ -50423,8 +50804,6 @@ var require_ipv6 = __commonJS({ /** * Generate a regular expression that can be used to find or validate all * variations of this address. - * @memberof Address6 - * @instance * @param {boolean} substringSearch * @returns {RegExp} */ @@ -50433,6 +50812,15 @@ var require_ipv6 = __commonJS({ } }; exports2.Address6 = Address6; + var TYPE_SUBNETS = Object.keys(constants6.TYPES).map((subnet) => [ + new Address6(subnet), + constants6.TYPES[subnet] + ]); + var TEREDO_SUBNET = new Address6("2001::/32"); + var SIX_TO_FOUR_SUBNET = new Address6("2002::/16"); + var ULA_SUBNET = new Address6("fc00::/7"); + var DOCUMENTATION_SUBNET = new Address6("2001:db8::/32"); + var IPV4_MAPPED_SUBNET = new Address6("::ffff:0:0/96"); } });