Download node_modules/ip-address/dist/ipv6.js from Snapkitty/agentscope-sift: direct link, hf CLI and curl.
- Browser
- Download file 48.3 kB
-
https://huggingface.co/Snapkitty/agentscope-sift/resolve/main/node_modules/ip-address/dist/ipv6.js
- Command line
-
hf download hf://Snapkitty/agentscope-sift/node_modules/ip-address/dist/ipv6.js
-
curl -L -o ipv6.js https://huggingface.co/Snapkitty/agentscope-sift/resolve/main/node_modules/ip-address/dist/ipv6.js
48.3 kB
| ; | |
| /* eslint-disable prefer-destructuring */ | |
| /* eslint-disable no-param-reassign */ | |
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | |
| if (k2 === undefined) k2 = k; | |
| var desc = Object.getOwnPropertyDescriptor(m, k); | |
| if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | |
| desc = { enumerable: true, get: function() { return m[k]; } }; | |
| } | |
| Object.defineProperty(o, k2, desc); | |
| }) : (function(o, m, k, k2) { | |
| if (k2 === undefined) k2 = k; | |
| o[k2] = m[k]; | |
| })); | |
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | |
| Object.defineProperty(o, "default", { enumerable: true, value: v }); | |
| }) : function(o, v) { | |
| o["default"] = v; | |
| }); | |
| var __importStar = (this && this.__importStar) || function (mod) { | |
| if (mod && mod.__esModule) return mod; | |
| var result = {}; | |
| if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | |
| __setModuleDefault(result, mod); | |
| return result; | |
| }; | |
| Object.defineProperty(exports, "__esModule", { value: true }); | |
| exports.Address6 = void 0; | |
| const common = __importStar(require("./common")); | |
| const constants4 = __importStar(require("./v4/constants")); | |
| const constants6 = __importStar(require("./v6/constants")); | |
| const helpers = __importStar(require("./v6/helpers")); | |
| const ipv4_1 = require("./ipv4"); | |
| const regular_expressions_1 = require("./v6/regular-expressions"); | |
| const address_error_1 = require("./address-error"); | |
| const common_1 = require("./common"); | |
| const isCorrect6 = common.isCorrect(constants6.BITS); | |
| function assert(condition) { | |
| if (!condition) { | |
| throw new Error('Assertion failed.'); | |
| } | |
| } | |
| function addCommas(number) { | |
| const r = /(\d+)(\d{3})/; | |
| while (r.test(number)) { | |
| number = number.replace(r, '$1,$2'); | |
| } | |
| return number; | |
| } | |
| function spanLeadingZeroes4(n) { | |
| n = n.replace(/^(0{1,})([1-9]+)$/, '<span class="parse-error">$1</span>$2'); | |
| n = n.replace(/^(0{1,})(0)$/, '<span class="parse-error">$1</span>$2'); | |
| return n; | |
| } | |
| /* | |
| * A helper function to compact an array | |
| */ | |
| function compact(address, slice) { | |
| const s1 = []; | |
| const s2 = []; | |
| let i; | |
| for (i = 0; i < address.length; i++) { | |
| if (i < slice[0]) { | |
| s1.push(address[i]); | |
| } | |
| else if (i > slice[1]) { | |
| s2.push(address[i]); | |
| } | |
| } | |
| return s1.concat(['compact']).concat(s2); | |
| } | |
| function paddedHex(octet) { | |
| return parseInt(octet, 16).toString(16).padStart(4, '0'); | |
| } | |
| function unsignByte(b) { | |
| // eslint-disable-next-line no-bitwise | |
| return b & 0xff; | |
| } | |
| /** | |
| * Represents an IPv6 address | |
| * @param {string} address - An IPv6 address string | |
| * @param {number} [groups=8] - How many octets to parse | |
| * @example | |
| * var address = new Address6('2001::/32'); | |
| */ | |
| class Address6 { | |
| constructor(address, optionalGroups) { | |
| this.addressMinusSuffix = ''; | |
| this.parsedSubnet = ''; | |
| this.subnet = '/128'; | |
| this.subnetMask = 128; | |
| this.v4 = false; | |
| this.zone = ''; | |
| // #region Attributes | |
| /** | |
| * Returns true if the given address is in the subnet of the current address | |
| * @returns {boolean} | |
| */ | |
| this.isInSubnet = common.isInSubnet; | |
| /** | |
| * Returns true if the address is correct, false otherwise | |
| * @returns {boolean} | |
| */ | |
| this.isCorrect = isCorrect6; | |
| if (optionalGroups === undefined) { | |
| this.groups = constants6.GROUPS; | |
| } | |
| else { | |
| this.groups = optionalGroups; | |
| } | |
| this.address = address; | |
| const subnet = constants6.RE_SUBNET_STRING.exec(address); | |
| if (subnet) { | |
| this.parsedSubnet = subnet[0].replace('/', ''); | |
| this.subnetMask = parseInt(this.parsedSubnet, 10); | |
| this.subnet = `/${this.subnetMask}`; | |
| if (Number.isNaN(this.subnetMask) || | |
| this.subnetMask < 0 || | |
| this.subnetMask > constants6.BITS) { | |
| throw new address_error_1.AddressError('Invalid subnet mask.'); | |
| } | |
| address = address.replace(constants6.RE_SUBNET_STRING, ''); | |
| } | |
| else if (/\//.test(address)) { | |
| throw new address_error_1.AddressError('Invalid subnet mask.'); | |
| } | |
| const zone = constants6.RE_ZONE_STRING.exec(address); | |
| if (zone) { | |
| this.zone = zone[0]; | |
| address = address.replace(constants6.RE_ZONE_STRING, ''); | |
| } | |
| 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 { | |
| // eslint-disable-next-line no-new | |
| new Address6(address); | |
| return true; | |
| } | |
| catch (e) { | |
| return false; | |
| } | |
| } | |
| /** | |
| * 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 | |
| * var bigInt = BigInt('1000000000000'); | |
| * var address = Address6.fromBigInt(bigInt); | |
| * 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 = []; | |
| for (let i = 0; i < constants6.GROUPS; i++) { | |
| groups.push(hex.slice(i * 4, (i + 1) * 4)); | |
| } | |
| return new Address6(groups.join(':')); | |
| } | |
| /** | |
| * 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::' | |
| * addressAndPort.port; // 8080 | |
| */ | |
| static fromURL(url) { | |
| let host; | |
| let port = null; | |
| let result; | |
| // If we have brackets parse them and find a port | |
| if (url.indexOf('[') !== -1 && url.indexOf(']:') !== -1) { | |
| result = constants6.RE_URL_WITH_PORT.exec(url); | |
| if (result === null) { | |
| return { | |
| error: 'failed to parse address with port', | |
| address: null, | |
| port: null, | |
| }; | |
| } | |
| host = result[1]; | |
| port = result[2]; | |
| // If there's a URL extract the address | |
| } | |
| else if (url.indexOf('/') !== -1) { | |
| // Remove the protocol prefix | |
| url = url.replace(/^[a-z0-9]+:\/\//, ''); | |
| // Parse the address | |
| result = constants6.RE_URL.exec(url); | |
| if (result === null) { | |
| return { | |
| error: 'failed to parse address from URL', | |
| address: null, | |
| port: null, | |
| }; | |
| } | |
| host = result[1]; | |
| // Otherwise just assign the URL to the host and let the library parse it | |
| } | |
| else { | |
| host = url; | |
| } | |
| // If there's a port convert it to an integer | |
| if (port) { | |
| port = parseInt(port, 10); | |
| // squelch out of range ports | |
| if (port < 0 || port > 65536) { | |
| port = null; | |
| } | |
| } | |
| else { | |
| // Standardize `undefined` to `null` | |
| port = null; | |
| } | |
| return { | |
| address: new Address6(host), | |
| 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); | |
| // eslint-disable-next-line no-bitwise | |
| 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 i = 0; i < groups.length; i++) { | |
| if (groups[i] === '*') { | |
| if (firstWildcard === -1) { | |
| firstWildcard = i; | |
| } | |
| } | |
| 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((g) => (g === '*' ? '0' : g)); | |
| const subnetBits = constants6.BITS - trailing * 16; | |
| return new Address6(`${replaced.join(':')}/${subnetBits}`); | |
| } | |
| /** | |
| * Create an IPv6-mapped address given an IPv4 address | |
| * @param {string} address - An IPv4 address string | |
| * @returns {Address6} | |
| * @example | |
| * var address = Address6.fromAddress4('192.168.0.1'); | |
| * address.correctForm(); // '::ffff:c0a8:1' | |
| * address.to4in6(); // '::ffff:192.168.0.1' | |
| */ | |
| static fromAddress4(address) { | |
| const address4 = new ipv4_1.Address4(address); | |
| const mask6 = constants6.BITS - (constants4.BITS - address4.subnetMask); | |
| return new Address6(`::ffff:${address4.correctForm()}/${mask6}`); | |
| } | |
| /** | |
| * Return an address from ip6.arpa form | |
| * @param {string} arpaFormAddress - an 'ip6.arpa' form address | |
| * @returns {Adress6} | |
| * @example | |
| * var address = Address6.fromArpa(e.f.f.f.3.c.2.6.f.f.f.e.6.6.8.e.1.0.6.7.9.4.e.c.0.0.0.0.1.0.0.2.ip6.arpa.) | |
| * address.correctForm(); // '2001:0:ce49:7601:e866:efff:62c3:fffe' | |
| */ | |
| static fromArpa(arpaFormAddress) { | |
| // remove ending ".ip6.arpa." or just "." | |
| let address = arpaFormAddress.replace(/(\.ip6\.arpa)?\.$/, ''); | |
| const semicolonAmount = 7; | |
| // correct ip6.arpa form with ending removed will be 63 characters | |
| if (address.length !== 63) { | |
| throw new address_error_1.AddressError("Invalid 'ip6.arpa' form."); | |
| } | |
| const parts = address.split('.').reverse(); | |
| for (let i = semicolonAmount; i > 0; i--) { | |
| const insertIndex = i * 4; | |
| parts.splice(insertIndex, 0, ':'); | |
| } | |
| address = parts.join(''); | |
| return new Address6(address); | |
| } | |
| /** | |
| * Return the Microsoft UNC transcription of the address | |
| * @returns {String} the Microsoft UNC transcription of the address | |
| */ | |
| microsoftTranscription() { | |
| return `${this.correctForm().replace(/:/g, '-')}.ipv6-literal.net`; | |
| } | |
| /** | |
| * Return the first n bits of the address, defaulting to the subnet mask | |
| * @param {number} [mask=subnet] - the number of bits to mask | |
| * @returns {String} the first n bits of the address as a string | |
| */ | |
| mask(mask = this.subnetMask) { | |
| return this.getBitsBase2(0, mask); | |
| } | |
| /** | |
| * Return the number of possible subnets of a given size in the address | |
| * @param {number} [subnetSize=128] - the subnet size | |
| * @returns {String} | |
| */ | |
| // TODO: probably useful to have a numeric version of this too | |
| possibleSubnets(subnetSize = 128) { | |
| const availableBits = constants6.BITS - this.subnetMask; | |
| const subnetBits = Math.abs(subnetSize - constants6.BITS); | |
| const subnetPowers = availableBits - subnetBits; | |
| if (subnetPowers < 0) { | |
| return '0'; | |
| } | |
| return addCommas((BigInt('2') ** BigInt(subnetPowers)).toString(10)); | |
| } | |
| /** | |
| * Helper function getting start address. | |
| * @returns {bigint} | |
| */ | |
| _startAddress() { | |
| return BigInt(`0b${this.mask() + '0'.repeat(constants6.BITS - this.subnetMask)}`); | |
| } | |
| /** | |
| * The first address in the range given by this address' subnet | |
| * Often referred to as the Network Address. | |
| * @returns {Address6} | |
| */ | |
| startAddress() { | |
| return Address6.fromBigInt(this._startAddress()); | |
| } | |
| /** | |
| * The first host address in the range given by this address's subnet ie | |
| * the first address after the Network Address | |
| * @returns {Address6} | |
| */ | |
| startAddressExclusive() { | |
| const adjust = BigInt('1'); | |
| return Address6.fromBigInt(this._startAddress() + adjust); | |
| } | |
| /** | |
| * Helper function getting end address. | |
| * @returns {bigint} | |
| */ | |
| _endAddress() { | |
| return BigInt(`0b${this.mask() + '1'.repeat(constants6.BITS - this.subnetMask)}`); | |
| } | |
| /** | |
| * The last address in the range given by this address' subnet | |
| * Often referred to as the Broadcast | |
| * @returns {Address6} | |
| */ | |
| endAddress() { | |
| return Address6.fromBigInt(this._endAddress()); | |
| } | |
| /** | |
| * The last host address in the range given by this address's subnet ie | |
| * the last address prior to the Broadcast Address | |
| * @returns {Address6} | |
| */ | |
| endAddressExclusive() { | |
| const adjust = BigInt('1'); | |
| return Address6.fromBigInt(this._endAddress() - adjust); | |
| } | |
| /** | |
| * 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() { | |
| 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'; | |
| } | |
| // RFC 4291 §2.5.3: the loopback address is treated as having Link-Local | |
| // scope. (Multicast scope 1, "Interface-Local", is a different concept | |
| // used only for loopback transmission of multicast.) | |
| if (type === 'Link-local unicast' || type === 'Loopback') { | |
| return 'Link local'; | |
| } | |
| // RFC 4007 §6: the unspecified address has no scope. | |
| if (type === 'Unspecified') { | |
| return 'Unknown'; | |
| } | |
| return 'Global'; | |
| } | |
| /** | |
| * Return the type of the address | |
| * @returns {String} | |
| */ | |
| getType() { | |
| for (let i = 0; i < TYPE_SUBNETS.length; i++) { | |
| const entry = TYPE_SUBNETS[i]; | |
| if (this.isInSubnet(entry[0])) { | |
| return entry[1]; | |
| } | |
| } | |
| return 'Global unicast'; | |
| } | |
| /** | |
| * Return the bits in the given range as a BigInt | |
| * @returns {bigint} | |
| */ | |
| getBits(start, end) { | |
| return BigInt(`0b${this.getBitsBase2(start, end)}`); | |
| } | |
| /** | |
| * Return the bits in the given range as a base-2 string | |
| * @returns {String} | |
| */ | |
| getBitsBase2(start, end) { | |
| return this.binaryZeroPad().slice(start, end); | |
| } | |
| /** | |
| * Return the bits in the given range as a base-16 string | |
| * @returns {String} | |
| */ | |
| getBitsBase16(start, end) { | |
| const length = end - start; | |
| if (length % 4 !== 0) { | |
| throw new Error('Length of bits to retrieve must be divisible by four'); | |
| } | |
| return this.getBits(start, end) | |
| .toString(16) | |
| .padStart(length / 4, '0'); | |
| } | |
| /** | |
| * Return the bits that are set past the subnet mask length | |
| * @returns {String} | |
| */ | |
| getBitsPastSubnet() { | |
| return this.getBitsBase2(this.subnetMask, constants6.BITS); | |
| } | |
| /** | |
| * Return the reversed ip6.arpa form of the address | |
| * @param {Object} options | |
| * @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix | |
| * @returns {String} | |
| */ | |
| reverseForm(options) { | |
| if (!options) { | |
| options = {}; | |
| } | |
| const characters = Math.floor(this.subnetMask / 4); | |
| const reversed = this.canonicalForm() | |
| .replace(/:/g, '') | |
| .split('') | |
| .slice(0, characters) | |
| .reverse() | |
| .join('.'); | |
| if (characters > 0) { | |
| if (options.omitSuffix) { | |
| return reversed; | |
| } | |
| return `${reversed}.ip6.arpa.`; | |
| } | |
| if (options.omitSuffix) { | |
| return ''; | |
| } | |
| return 'ip6.arpa.'; | |
| } | |
| /** | |
| * 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 i; | |
| let groups = []; | |
| let zeroCounter = 0; | |
| const zeroes = []; | |
| for (i = 0; i < this.parsedAddress.length; i++) { | |
| const value = parseInt(this.parsedAddress[i], 16); | |
| if (value === 0) { | |
| zeroCounter++; | |
| } | |
| if (value !== 0 && zeroCounter > 0) { | |
| if (zeroCounter > 1) { | |
| zeroes.push([i - zeroCounter, i - 1]); | |
| } | |
| zeroCounter = 0; | |
| } | |
| } | |
| // Do we end with a string of zeroes? | |
| if (zeroCounter > 1) { | |
| zeroes.push([this.parsedAddress.length - zeroCounter, this.parsedAddress.length - 1]); | |
| } | |
| const zeroLengths = zeroes.map((n) => n[1] - n[0] + 1); | |
| if (zeroes.length > 0) { | |
| const index = zeroLengths.indexOf(Math.max(...zeroLengths)); | |
| groups = compact(this.parsedAddress, zeroes[index]); | |
| } | |
| else { | |
| groups = this.parsedAddress; | |
| } | |
| for (i = 0; i < groups.length; i++) { | |
| if (groups[i] !== 'compact') { | |
| groups[i] = parseInt(groups[i], 16).toString(16); | |
| } | |
| } | |
| let correct = groups.join(':'); | |
| correct = correct.replace(/^compact$/, '::'); | |
| correct = correct.replace(/(^compact)|(compact$)/, ':'); | |
| correct = correct.replace(/compact/, ''); | |
| return correct; | |
| } | |
| /** | |
| * Return a zero-padded base-2 string representation of the address | |
| * @returns {String} | |
| * @example | |
| * var address = new Address6('2001:4860:4001:803::1011'); | |
| * address.binaryZeroPad(); | |
| * // '0010000000000001010010000110000001000000000000010000100000000011 | |
| * // 0000000000000000000000000000000000000000000000000001000000010001' | |
| */ | |
| binaryZeroPad() { | |
| if (this._binaryZeroPad === undefined) { | |
| 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); | |
| if (address4) { | |
| this.parsedAddress4 = address4[0]; | |
| this.address4 = new ipv4_1.Address4(this.parsedAddress4); | |
| for (let i = 0; i < this.address4.groups; i++) { | |
| if (/^0[0-9]+/.test(this.address4.parsedAddress[i])) { | |
| // The prefix groups haven't been through the bad-character check | |
| // yet, so escape them before including in the error HTML. | |
| 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; | |
| groups[groups.length - 1] = this.address4.toGroup6(); | |
| address = groups.join(':'); | |
| } | |
| 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); | |
| const badCharacters = address.match(constants6.RE_BAD_CHARACTERS); | |
| if (badCharacters) { | |
| throw new address_error_1.AddressError(`Bad character${badCharacters.length > 1 ? 's' : ''} detected in address: ${badCharacters.join('')}`, address.replace(constants6.RE_BAD_CHARACTERS, '<span class="parse-error">$1</span>')); | |
| } | |
| const badAddress = address.match(constants6.RE_BAD_ADDRESS); | |
| if (badAddress) { | |
| throw new address_error_1.AddressError(`Address failed regex: ${badAddress.join('')}`, address.replace(constants6.RE_BAD_ADDRESS, '<span class="parse-error">$1</span>')); | |
| } | |
| let groups = []; | |
| const halves = address.split('::'); | |
| if (halves.length === 2) { | |
| let first = halves[0].split(':'); | |
| let last = halves[1].split(':'); | |
| if (first.length === 1 && first[0] === '') { | |
| first = []; | |
| } | |
| if (last.length === 1 && last[0] === '') { | |
| last = []; | |
| } | |
| const remaining = this.groups - (first.length + last.length); | |
| if (!remaining) { | |
| throw new address_error_1.AddressError('Error parsing groups'); | |
| } | |
| this.elidedGroups = remaining; | |
| this.elisionBegin = first.length; | |
| this.elisionEnd = first.length + this.elidedGroups; | |
| groups = groups.concat(first); | |
| for (let i = 0; i < remaining; i++) { | |
| groups.push('0'); | |
| } | |
| groups = groups.concat(last); | |
| } | |
| else if (halves.length === 1) { | |
| groups = address.split(':'); | |
| this.elidedGroups = 0; | |
| } | |
| else { | |
| throw new address_error_1.AddressError('Too many :: groups found'); | |
| } | |
| groups = groups.map((group) => parseInt(group, 16).toString(16)); | |
| if (groups.length !== this.groups) { | |
| throw new address_error_1.AddressError('Incorrect number of groups found'); | |
| } | |
| return groups; | |
| } | |
| /** | |
| * 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 | |
| * @returns {String} | |
| */ | |
| decimal() { | |
| return this.parsedAddress.map((n) => parseInt(n, 16).toString(10).padStart(5, '0')).join(':'); | |
| } | |
| /** | |
| * Return the address as a BigInt | |
| * @returns {bigint} | |
| */ | |
| bigInt() { | |
| return BigInt(`0x${this.parsedAddress.map(paddedHex).join('')}`); | |
| } | |
| /** | |
| * Return the last two groups of this address as an IPv4 address string | |
| * @returns {Address4} | |
| * @example | |
| * var address = new Address6('2001:4860:4001::1825:bf11'); | |
| * address.to4().correctForm(); // '24.37.191.17' | |
| */ | |
| to4() { | |
| const binary = this.binaryZeroPad().split(''); | |
| 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 | |
| * @returns {String} | |
| */ | |
| to4in6() { | |
| const address4 = this.to4(); | |
| const address6 = new Address6(this.parsedAddress.slice(0, 6).join(':'), 6); | |
| const correct = address6.correctForm(); | |
| let infix = ''; | |
| if (!/:$/.test(correct)) { | |
| infix = ':'; | |
| } | |
| return correct + infix + address4.address; | |
| } | |
| /** | |
| * 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() { | |
| /* | |
| - Bits 0 to 31 are set to the Teredo prefix (normally 2001:0000::/32). | |
| - Bits 32 to 63 embed the primary IPv4 address of the Teredo server that | |
| is used. | |
| - Bits 64 to 79 can be used to define some flags. Currently only the | |
| higher order bit is used; it is set to 1 if the Teredo client is | |
| located behind a cone NAT, 0 otherwise. For Microsoft's Windows Vista | |
| and Windows Server 2008 implementations, more bits are used. In those | |
| implementations, the format for these 16 bits is "CRAAAAUG AAAAAAAA", | |
| where "C" remains the "Cone" flag. The "R" bit is reserved for future | |
| use. The "U" bit is for the Universal/Local flag (set to 0). The "G" bit | |
| is Individual/Group flag (set to 0). The A bits are set to a 12-bit | |
| randomly generated number chosen by the Teredo client to introduce | |
| additional protection for the Teredo node against IPv6-based scanning | |
| attacks. | |
| - Bits 80 to 95 contains the obfuscated UDP port number. This is the | |
| port number that is mapped by the NAT to the Teredo client with all | |
| bits inverted. | |
| - Bits 96 to 127 contains the obfuscated IPv4 address. This is the | |
| public IPv4 address of the NAT with all bits inverted. | |
| */ | |
| const prefix = this.getBitsBase16(0, 32); | |
| const bitsForUdpPort = this.getBits(80, 96); | |
| // eslint-disable-next-line no-bitwise | |
| const udpPort = (bitsForUdpPort ^ BigInt('0xffff')).toString(); | |
| const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64)); | |
| const bitsForClient4 = this.getBits(96, 128); | |
| // eslint-disable-next-line no-bitwise | |
| 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); | |
| const groupIndividual = (0, common_1.testBit)(flagsBase2, 8); | |
| const universalLocal = (0, common_1.testBit)(flagsBase2, 9); | |
| const nonce = BigInt(`0b${flagsBase2.slice(2, 6) + flagsBase2.slice(8, 16)}`).toString(10); | |
| return { | |
| prefix: `${prefix.slice(0, 4)}:${prefix.slice(4, 8)}`, | |
| server4: server4.address, | |
| client4: client4.address, | |
| flags: flagsBase2, | |
| coneNat, | |
| microsoft: { | |
| reserved, | |
| universalLocal, | |
| groupIndividual, | |
| nonce, | |
| }, | |
| udpPort, | |
| }; | |
| } | |
| /** | |
| * 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() { | |
| /* | |
| - Bits 0 to 15 are set to the 6to4 prefix (2002::/16). | |
| - Bits 16 to 48 embed the IPv4 address of the 6to4 gateway that is used. | |
| */ | |
| const prefix = this.getBitsBase16(0, 16); | |
| const gateway = ipv4_1.Address4.fromHex(this.getBitsBase16(16, 48)); | |
| return { | |
| prefix: prefix.slice(0, 4), | |
| gateway: gateway.address, | |
| }; | |
| } | |
| /** | |
| * Return a v6 6to4 address from a v6 v4inv6 address | |
| * @returns {Address6} | |
| */ | |
| to6to4() { | |
| if (!this.is4()) { | |
| return null; | |
| } | |
| const addr6to4 = [ | |
| '2002', | |
| this.getBitsBase16(96, 112), | |
| this.getBitsBase16(112, 128), | |
| '', | |
| '/16', | |
| ].join(':'); | |
| return new Address6(addr6to4); | |
| } | |
| /** | |
| * 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 i = 0; i < 8; i++) { | |
| groups.push(hex.slice(i * 4, (i + 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 i = 0; i < 4; i++) { | |
| octets.push(parseInt(v4Bits.slice(i * 8, (i + 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() { | |
| const valueWithoutPadding = this.bigInt().toString(16); | |
| const leadingPad = '0'.repeat(valueWithoutPadding.length % 2); | |
| const value = `${leadingPad}${valueWithoutPadding}`; | |
| const bytes = []; | |
| for (let i = 0, length = value.length; i < length; i += 2) { | |
| bytes.push(parseInt(value.substring(i, i + 2), 16)); | |
| } | |
| return bytes; | |
| } | |
| /** | |
| * 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. | |
| * | |
| * 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. | |
| * | |
| * To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`. | |
| * @returns {Address6} | |
| */ | |
| static fromUnsignedByteArray(bytes) { | |
| const BYTE_MAX = BigInt('256'); | |
| let result = BigInt('0'); | |
| let multiplier = BigInt('1'); | |
| for (let i = bytes.length - 1; i >= 0; i--) { | |
| result += multiplier * BigInt(bytes[i].toString(10)); | |
| multiplier *= BYTE_MAX; | |
| } | |
| return Address6.fromBigInt(result); | |
| } | |
| /** | |
| * Returns true if the address is in the canonical form, false otherwise | |
| * @returns {boolean} | |
| */ | |
| isCanonical() { | |
| return this.addressMinusSuffix === this.canonicalForm(); | |
| } | |
| /** | |
| * Returns true if the address is a link local address, false otherwise | |
| * @returns {boolean} | |
| */ | |
| isLinkLocal() { | |
| // Zeroes are required, i.e. we can't check isInSubnet with 'fe80::/10' | |
| if (this.getBitsBase2(0, 64) === | |
| '1111111010000000000000000000000000000000000000000000000000000000') { | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * Returns true if the address is a multicast address, false otherwise | |
| * @returns {boolean} | |
| */ | |
| isMulticast() { | |
| const type = this.getType(); | |
| return type === 'Multicast' || type.startsWith('Multicast '); | |
| } | |
| /** | |
| * 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 | |
| * @returns {boolean} | |
| */ | |
| isTeredo() { | |
| return this.isInSubnet(TEREDO_SUBNET); | |
| } | |
| /** | |
| * Returns true if the address is a 6to4 address, false otherwise | |
| * @returns {boolean} | |
| */ | |
| is6to4() { | |
| return this.isInSubnet(SIX_TO_FOUR_SUBNET); | |
| } | |
| /** | |
| * Returns true if the address is a loopback address, false otherwise | |
| * @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 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 === undefined) { | |
| optionalPort = ''; | |
| } | |
| else { | |
| optionalPort = `:${optionalPort}`; | |
| } | |
| return `http://[${this.correctForm()}]${optionalPort}/`; | |
| } | |
| /** | |
| * Returns an HTML `<a>` 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 `<a>` 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) { | |
| options = {}; | |
| } | |
| if (options.className === undefined) { | |
| options.className = ''; | |
| } | |
| if (options.prefix === undefined) { | |
| options.prefix = '/#address='; | |
| } | |
| if (options.v4 === undefined) { | |
| options.v4 = false; | |
| } | |
| let formFunction = this.correctForm; | |
| if (options.v4) { | |
| formFunction = this.to4in6; | |
| } | |
| const form = formFunction.call(this); | |
| const safeHref = helpers.escapeHtml(`${options.prefix}${form}`); | |
| const safeForm = helpers.escapeHtml(form); | |
| if (options.className) { | |
| const safeClass = helpers.escapeHtml(options.className); | |
| return `<a href="${safeHref}" class="${safeClass}">${safeForm}</a>`; | |
| } | |
| return `<a href="${safeHref}">${safeForm}</a>`; | |
| } | |
| /** | |
| * Groups an address | |
| * @returns {String} | |
| */ | |
| group() { | |
| if (this.elidedGroups === 0) { | |
| // The simple case | |
| return helpers.simpleGroup(this.addressMinusSuffix).join(':'); | |
| } | |
| assert(typeof this.elidedGroups === 'number'); | |
| assert(typeof this.elisionBegin === 'number'); | |
| // The elided case | |
| const output = []; | |
| const [left, right] = this.addressMinusSuffix.split('::'); | |
| if (left.length) { | |
| output.push(...helpers.simpleGroup(left)); | |
| } | |
| else { | |
| output.push(''); | |
| } | |
| const classes = ['hover-group']; | |
| for (let i = this.elisionBegin; i < this.elisionBegin + this.elidedGroups; i++) { | |
| classes.push(`group-${i}`); | |
| } | |
| output.push(`<span class="${classes.join(' ')}"></span>`); | |
| if (right.length) { | |
| output.push(...helpers.simpleGroup(right, this.elisionEnd)); | |
| } | |
| else { | |
| output.push(''); | |
| } | |
| if (this.is4()) { | |
| assert(this.address4 instanceof ipv4_1.Address4); | |
| output.pop(); | |
| output.push(this.address4.groupForV6()); | |
| } | |
| return output.join(':'); | |
| } | |
| // #endregion | |
| // #region Regular expressions | |
| /** | |
| * Generate a regular expression string that can be used to find or validate | |
| * all variations of this address | |
| * @param {boolean} substringSearch | |
| * @returns {string} | |
| */ | |
| regularExpressionString(substringSearch = false) { | |
| let output = []; | |
| // TODO: revisit why this is necessary | |
| const address6 = new Address6(this.correctForm()); | |
| if (address6.elidedGroups === 0) { | |
| // The simple case | |
| output.push((0, regular_expressions_1.simpleRegularExpression)(address6.parsedAddress)); | |
| } | |
| else if (address6.elidedGroups === constants6.GROUPS) { | |
| // A completely elided address | |
| output.push((0, regular_expressions_1.possibleElisions)(constants6.GROUPS)); | |
| } | |
| else { | |
| // A partially elided address | |
| const halves = address6.address.split('::'); | |
| if (halves[0].length) { | |
| output.push((0, regular_expressions_1.simpleRegularExpression)(halves[0].split(':'))); | |
| } | |
| assert(typeof address6.elidedGroups === 'number'); | |
| output.push((0, regular_expressions_1.possibleElisions)(address6.elidedGroups, halves[0].length !== 0, halves[1].length !== 0)); | |
| if (halves[1].length) { | |
| output.push((0, regular_expressions_1.simpleRegularExpression)(halves[1].split(':'))); | |
| } | |
| output = [output.join(':')]; | |
| } | |
| if (!substringSearch) { | |
| output = [ | |
| '(?=^|', | |
| regular_expressions_1.ADDRESS_BOUNDARY, | |
| '|[^\\w\\:])(', | |
| ...output, | |
| ')(?=[^\\w\\:]|', | |
| regular_expressions_1.ADDRESS_BOUNDARY, | |
| '|$)', | |
| ]; | |
| } | |
| return output.join(''); | |
| } | |
| /** | |
| * Generate a regular expression that can be used to find or validate all | |
| * variations of this address. | |
| * @param {boolean} substringSearch | |
| * @returns {RegExp} | |
| */ | |
| regularExpression(substringSearch = false) { | |
| return new RegExp(this.regularExpressionString(substringSearch), 'i'); | |
| } | |
| } | |
| exports.Address6 = Address6; | |
| const TYPE_SUBNETS = Object.keys(constants6.TYPES).map((subnet) => [ | |
| new Address6(subnet), | |
| constants6.TYPES[subnet], | |
| ]); | |
| const TEREDO_SUBNET = new Address6('2001::/32'); | |
| const SIX_TO_FOUR_SUBNET = new Address6('2002::/16'); | |
| const ULA_SUBNET = new Address6('fc00::/7'); | |
| const DOCUMENTATION_SUBNET = new Address6('2001:db8::/32'); | |
| const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96'); | |
| //# sourceMappingURL=ipv6.js.map |