source: node_modules/ip-address/dist/ipv6.js@ 62b2964

finki-main main
Last change on this file since 62b2964 was 81bc7da, checked in by Klimentina Efremova <klimentina08642@…>, 3 months ago

Initial commit

  • Property mode set to 100644
File size: 33.3 KB
Line 
1"use strict";
2/* eslint-disable prefer-destructuring */
3/* eslint-disable no-param-reassign */
4var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5 if (k2 === undefined) k2 = k;
6 var desc = Object.getOwnPropertyDescriptor(m, k);
7 if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8 desc = { enumerable: true, get: function() { return m[k]; } };
9 }
10 Object.defineProperty(o, k2, desc);
11}) : (function(o, m, k, k2) {
12 if (k2 === undefined) k2 = k;
13 o[k2] = m[k];
14}));
15var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16 Object.defineProperty(o, "default", { enumerable: true, value: v });
17}) : function(o, v) {
18 o["default"] = v;
19});
20var __importStar = (this && this.__importStar) || function (mod) {
21 if (mod && mod.__esModule) return mod;
22 var result = {};
23 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
24 __setModuleDefault(result, mod);
25 return result;
26};
27Object.defineProperty(exports, "__esModule", { value: true });
28exports.Address6 = void 0;
29const common = __importStar(require("./common"));
30const constants4 = __importStar(require("./v4/constants"));
31const constants6 = __importStar(require("./v6/constants"));
32const helpers = __importStar(require("./v6/helpers"));
33const ipv4_1 = require("./ipv4");
34const regular_expressions_1 = require("./v6/regular-expressions");
35const address_error_1 = require("./address-error");
36const common_1 = require("./common");
37function assert(condition) {
38 if (!condition) {
39 throw new Error('Assertion failed.');
40 }
41}
42function addCommas(number) {
43 const r = /(\d+)(\d{3})/;
44 while (r.test(number)) {
45 number = number.replace(r, '$1,$2');
46 }
47 return number;
48}
49function spanLeadingZeroes4(n) {
50 n = n.replace(/^(0{1,})([1-9]+)$/, '<span class="parse-error">$1</span>$2');
51 n = n.replace(/^(0{1,})(0)$/, '<span class="parse-error">$1</span>$2');
52 return n;
53}
54/*
55 * A helper function to compact an array
56 */
57function compact(address, slice) {
58 const s1 = [];
59 const s2 = [];
60 let i;
61 for (i = 0; i < address.length; i++) {
62 if (i < slice[0]) {
63 s1.push(address[i]);
64 }
65 else if (i > slice[1]) {
66 s2.push(address[i]);
67 }
68 }
69 return s1.concat(['compact']).concat(s2);
70}
71function paddedHex(octet) {
72 return parseInt(octet, 16).toString(16).padStart(4, '0');
73}
74function unsignByte(b) {
75 // eslint-disable-next-line no-bitwise
76 return b & 0xff;
77}
78/**
79 * Represents an IPv6 address
80 * @class Address6
81 * @param {string} address - An IPv6 address string
82 * @param {number} [groups=8] - How many octets to parse
83 * @example
84 * var address = new Address6('2001::/32');
85 */
86class Address6 {
87 constructor(address, optionalGroups) {
88 this.addressMinusSuffix = '';
89 this.parsedSubnet = '';
90 this.subnet = '/128';
91 this.subnetMask = 128;
92 this.v4 = false;
93 this.zone = '';
94 // #region Attributes
95 /**
96 * Returns true if the given address is in the subnet of the current address
97 * @memberof Address6
98 * @instance
99 * @returns {boolean}
100 */
101 this.isInSubnet = common.isInSubnet;
102 /**
103 * Returns true if the address is correct, false otherwise
104 * @memberof Address6
105 * @instance
106 * @returns {boolean}
107 */
108 this.isCorrect = common.isCorrect(constants6.BITS);
109 if (optionalGroups === undefined) {
110 this.groups = constants6.GROUPS;
111 }
112 else {
113 this.groups = optionalGroups;
114 }
115 this.address = address;
116 const subnet = constants6.RE_SUBNET_STRING.exec(address);
117 if (subnet) {
118 this.parsedSubnet = subnet[0].replace('/', '');
119 this.subnetMask = parseInt(this.parsedSubnet, 10);
120 this.subnet = `/${this.subnetMask}`;
121 if (Number.isNaN(this.subnetMask) ||
122 this.subnetMask < 0 ||
123 this.subnetMask > constants6.BITS) {
124 throw new address_error_1.AddressError('Invalid subnet mask.');
125 }
126 address = address.replace(constants6.RE_SUBNET_STRING, '');
127 }
128 else if (/\//.test(address)) {
129 throw new address_error_1.AddressError('Invalid subnet mask.');
130 }
131 const zone = constants6.RE_ZONE_STRING.exec(address);
132 if (zone) {
133 this.zone = zone[0];
134 address = address.replace(constants6.RE_ZONE_STRING, '');
135 }
136 this.addressMinusSuffix = address;
137 this.parsedAddress = this.parse(this.addressMinusSuffix);
138 }
139 static isValid(address) {
140 try {
141 // eslint-disable-next-line no-new
142 new Address6(address);
143 return true;
144 }
145 catch (e) {
146 return false;
147 }
148 }
149 /**
150 * Convert a BigInt to a v6 address object
151 * @memberof Address6
152 * @static
153 * @param {bigint} bigInt - a BigInt to convert
154 * @returns {Address6}
155 * @example
156 * var bigInt = BigInt('1000000000000');
157 * var address = Address6.fromBigInt(bigInt);
158 * address.correctForm(); // '::e8:d4a5:1000'
159 */
160 static fromBigInt(bigInt) {
161 const hex = bigInt.toString(16).padStart(32, '0');
162 const groups = [];
163 let i;
164 for (i = 0; i < constants6.GROUPS; i++) {
165 groups.push(hex.slice(i * 4, (i + 1) * 4));
166 }
167 return new Address6(groups.join(':'));
168 }
169 /**
170 * Convert a URL (with optional port number) to an address object
171 * @memberof Address6
172 * @static
173 * @param {string} url - a URL with optional port number
174 * @example
175 * var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/');
176 * addressAndPort.address.correctForm(); // 'ffff::'
177 * addressAndPort.port; // 8080
178 */
179 static fromURL(url) {
180 let host;
181 let port = null;
182 let result;
183 // If we have brackets parse them and find a port
184 if (url.indexOf('[') !== -1 && url.indexOf(']:') !== -1) {
185 result = constants6.RE_URL_WITH_PORT.exec(url);
186 if (result === null) {
187 return {
188 error: 'failed to parse address with port',
189 address: null,
190 port: null,
191 };
192 }
193 host = result[1];
194 port = result[2];
195 // If there's a URL extract the address
196 }
197 else if (url.indexOf('/') !== -1) {
198 // Remove the protocol prefix
199 url = url.replace(/^[a-z0-9]+:\/\//, '');
200 // Parse the address
201 result = constants6.RE_URL.exec(url);
202 if (result === null) {
203 return {
204 error: 'failed to parse address from URL',
205 address: null,
206 port: null,
207 };
208 }
209 host = result[1];
210 // Otherwise just assign the URL to the host and let the library parse it
211 }
212 else {
213 host = url;
214 }
215 // If there's a port convert it to an integer
216 if (port) {
217 port = parseInt(port, 10);
218 // squelch out of range ports
219 if (port < 0 || port > 65536) {
220 port = null;
221 }
222 }
223 else {
224 // Standardize `undefined` to `null`
225 port = null;
226 }
227 return {
228 address: new Address6(host),
229 port,
230 };
231 }
232 /**
233 * Create an IPv6-mapped address given an IPv4 address
234 * @memberof Address6
235 * @static
236 * @param {string} address - An IPv4 address string
237 * @returns {Address6}
238 * @example
239 * var address = Address6.fromAddress4('192.168.0.1');
240 * address.correctForm(); // '::ffff:c0a8:1'
241 * address.to4in6(); // '::ffff:192.168.0.1'
242 */
243 static fromAddress4(address) {
244 const address4 = new ipv4_1.Address4(address);
245 const mask6 = constants6.BITS - (constants4.BITS - address4.subnetMask);
246 return new Address6(`::ffff:${address4.correctForm()}/${mask6}`);
247 }
248 /**
249 * Return an address from ip6.arpa form
250 * @memberof Address6
251 * @static
252 * @param {string} arpaFormAddress - an 'ip6.arpa' form address
253 * @returns {Adress6}
254 * @example
255 * 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.)
256 * address.correctForm(); // '2001:0:ce49:7601:e866:efff:62c3:fffe'
257 */
258 static fromArpa(arpaFormAddress) {
259 // remove ending ".ip6.arpa." or just "."
260 let address = arpaFormAddress.replace(/(\.ip6\.arpa)?\.$/, '');
261 const semicolonAmount = 7;
262 // correct ip6.arpa form with ending removed will be 63 characters
263 if (address.length !== 63) {
264 throw new address_error_1.AddressError("Invalid 'ip6.arpa' form.");
265 }
266 const parts = address.split('.').reverse();
267 for (let i = semicolonAmount; i > 0; i--) {
268 const insertIndex = i * 4;
269 parts.splice(insertIndex, 0, ':');
270 }
271 address = parts.join('');
272 return new Address6(address);
273 }
274 /**
275 * Return the Microsoft UNC transcription of the address
276 * @memberof Address6
277 * @instance
278 * @returns {String} the Microsoft UNC transcription of the address
279 */
280 microsoftTranscription() {
281 return `${this.correctForm().replace(/:/g, '-')}.ipv6-literal.net`;
282 }
283 /**
284 * Return the first n bits of the address, defaulting to the subnet mask
285 * @memberof Address6
286 * @instance
287 * @param {number} [mask=subnet] - the number of bits to mask
288 * @returns {String} the first n bits of the address as a string
289 */
290 mask(mask = this.subnetMask) {
291 return this.getBitsBase2(0, mask);
292 }
293 /**
294 * Return the number of possible subnets of a given size in the address
295 * @memberof Address6
296 * @instance
297 * @param {number} [subnetSize=128] - the subnet size
298 * @returns {String}
299 */
300 // TODO: probably useful to have a numeric version of this too
301 possibleSubnets(subnetSize = 128) {
302 const availableBits = constants6.BITS - this.subnetMask;
303 const subnetBits = Math.abs(subnetSize - constants6.BITS);
304 const subnetPowers = availableBits - subnetBits;
305 if (subnetPowers < 0) {
306 return '0';
307 }
308 return addCommas((BigInt('2') ** BigInt(subnetPowers)).toString(10));
309 }
310 /**
311 * Helper function getting start address.
312 * @memberof Address6
313 * @instance
314 * @returns {bigint}
315 */
316 _startAddress() {
317 return BigInt(`0b${this.mask() + '0'.repeat(constants6.BITS - this.subnetMask)}`);
318 }
319 /**
320 * The first address in the range given by this address' subnet
321 * Often referred to as the Network Address.
322 * @memberof Address6
323 * @instance
324 * @returns {Address6}
325 */
326 startAddress() {
327 return Address6.fromBigInt(this._startAddress());
328 }
329 /**
330 * The first host address in the range given by this address's subnet ie
331 * the first address after the Network Address
332 * @memberof Address6
333 * @instance
334 * @returns {Address6}
335 */
336 startAddressExclusive() {
337 const adjust = BigInt('1');
338 return Address6.fromBigInt(this._startAddress() + adjust);
339 }
340 /**
341 * Helper function getting end address.
342 * @memberof Address6
343 * @instance
344 * @returns {bigint}
345 */
346 _endAddress() {
347 return BigInt(`0b${this.mask() + '1'.repeat(constants6.BITS - this.subnetMask)}`);
348 }
349 /**
350 * The last address in the range given by this address' subnet
351 * Often referred to as the Broadcast
352 * @memberof Address6
353 * @instance
354 * @returns {Address6}
355 */
356 endAddress() {
357 return Address6.fromBigInt(this._endAddress());
358 }
359 /**
360 * The last host address in the range given by this address's subnet ie
361 * the last address prior to the Broadcast Address
362 * @memberof Address6
363 * @instance
364 * @returns {Address6}
365 */
366 endAddressExclusive() {
367 const adjust = BigInt('1');
368 return Address6.fromBigInt(this._endAddress() - adjust);
369 }
370 /**
371 * Return the scope of the address
372 * @memberof Address6
373 * @instance
374 * @returns {String}
375 */
376 getScope() {
377 let scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
378 if (this.getType() === 'Global unicast' && scope !== 'Link local') {
379 scope = 'Global';
380 }
381 return scope || 'Unknown';
382 }
383 /**
384 * Return the type of the address
385 * @memberof Address6
386 * @instance
387 * @returns {String}
388 */
389 getType() {
390 for (const subnet of Object.keys(constants6.TYPES)) {
391 if (this.isInSubnet(new Address6(subnet))) {
392 return constants6.TYPES[subnet];
393 }
394 }
395 return 'Global unicast';
396 }
397 /**
398 * Return the bits in the given range as a BigInt
399 * @memberof Address6
400 * @instance
401 * @returns {bigint}
402 */
403 getBits(start, end) {
404 return BigInt(`0b${this.getBitsBase2(start, end)}`);
405 }
406 /**
407 * Return the bits in the given range as a base-2 string
408 * @memberof Address6
409 * @instance
410 * @returns {String}
411 */
412 getBitsBase2(start, end) {
413 return this.binaryZeroPad().slice(start, end);
414 }
415 /**
416 * Return the bits in the given range as a base-16 string
417 * @memberof Address6
418 * @instance
419 * @returns {String}
420 */
421 getBitsBase16(start, end) {
422 const length = end - start;
423 if (length % 4 !== 0) {
424 throw new Error('Length of bits to retrieve must be divisible by four');
425 }
426 return this.getBits(start, end)
427 .toString(16)
428 .padStart(length / 4, '0');
429 }
430 /**
431 * Return the bits that are set past the subnet mask length
432 * @memberof Address6
433 * @instance
434 * @returns {String}
435 */
436 getBitsPastSubnet() {
437 return this.getBitsBase2(this.subnetMask, constants6.BITS);
438 }
439 /**
440 * Return the reversed ip6.arpa form of the address
441 * @memberof Address6
442 * @param {Object} options
443 * @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
444 * @instance
445 * @returns {String}
446 */
447 reverseForm(options) {
448 if (!options) {
449 options = {};
450 }
451 const characters = Math.floor(this.subnetMask / 4);
452 const reversed = this.canonicalForm()
453 .replace(/:/g, '')
454 .split('')
455 .slice(0, characters)
456 .reverse()
457 .join('.');
458 if (characters > 0) {
459 if (options.omitSuffix) {
460 return reversed;
461 }
462 return `${reversed}.ip6.arpa.`;
463 }
464 if (options.omitSuffix) {
465 return '';
466 }
467 return 'ip6.arpa.';
468 }
469 /**
470 * Return the correct form of the address
471 * @memberof Address6
472 * @instance
473 * @returns {String}
474 */
475 correctForm() {
476 let i;
477 let groups = [];
478 let zeroCounter = 0;
479 const zeroes = [];
480 for (i = 0; i < this.parsedAddress.length; i++) {
481 const value = parseInt(this.parsedAddress[i], 16);
482 if (value === 0) {
483 zeroCounter++;
484 }
485 if (value !== 0 && zeroCounter > 0) {
486 if (zeroCounter > 1) {
487 zeroes.push([i - zeroCounter, i - 1]);
488 }
489 zeroCounter = 0;
490 }
491 }
492 // Do we end with a string of zeroes?
493 if (zeroCounter > 1) {
494 zeroes.push([this.parsedAddress.length - zeroCounter, this.parsedAddress.length - 1]);
495 }
496 const zeroLengths = zeroes.map((n) => n[1] - n[0] + 1);
497 if (zeroes.length > 0) {
498 const index = zeroLengths.indexOf(Math.max(...zeroLengths));
499 groups = compact(this.parsedAddress, zeroes[index]);
500 }
501 else {
502 groups = this.parsedAddress;
503 }
504 for (i = 0; i < groups.length; i++) {
505 if (groups[i] !== 'compact') {
506 groups[i] = parseInt(groups[i], 16).toString(16);
507 }
508 }
509 let correct = groups.join(':');
510 correct = correct.replace(/^compact$/, '::');
511 correct = correct.replace(/(^compact)|(compact$)/, ':');
512 correct = correct.replace(/compact/, '');
513 return correct;
514 }
515 /**
516 * Return a zero-padded base-2 string representation of the address
517 * @memberof Address6
518 * @instance
519 * @returns {String}
520 * @example
521 * var address = new Address6('2001:4860:4001:803::1011');
522 * address.binaryZeroPad();
523 * // '0010000000000001010010000110000001000000000000010000100000000011
524 * // 0000000000000000000000000000000000000000000000000001000000010001'
525 */
526 binaryZeroPad() {
527 return this.bigInt().toString(2).padStart(constants6.BITS, '0');
528 }
529 // TODO: Improve the semantics of this helper function
530 parse4in6(address) {
531 const groups = address.split(':');
532 const lastGroup = groups.slice(-1)[0];
533 const address4 = lastGroup.match(constants4.RE_ADDRESS);
534 if (address4) {
535 this.parsedAddress4 = address4[0];
536 this.address4 = new ipv4_1.Address4(this.parsedAddress4);
537 for (let i = 0; i < this.address4.groups; i++) {
538 if (/^0[0-9]+/.test(this.address4.parsedAddress[i])) {
539 throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", address.replace(constants4.RE_ADDRESS, this.address4.parsedAddress.map(spanLeadingZeroes4).join('.')));
540 }
541 }
542 this.v4 = true;
543 groups[groups.length - 1] = this.address4.toGroup6();
544 address = groups.join(':');
545 }
546 return address;
547 }
548 // TODO: Make private?
549 parse(address) {
550 address = this.parse4in6(address);
551 const badCharacters = address.match(constants6.RE_BAD_CHARACTERS);
552 if (badCharacters) {
553 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>'));
554 }
555 const badAddress = address.match(constants6.RE_BAD_ADDRESS);
556 if (badAddress) {
557 throw new address_error_1.AddressError(`Address failed regex: ${badAddress.join('')}`, address.replace(constants6.RE_BAD_ADDRESS, '<span class="parse-error">$1</span>'));
558 }
559 let groups = [];
560 const halves = address.split('::');
561 if (halves.length === 2) {
562 let first = halves[0].split(':');
563 let last = halves[1].split(':');
564 if (first.length === 1 && first[0] === '') {
565 first = [];
566 }
567 if (last.length === 1 && last[0] === '') {
568 last = [];
569 }
570 const remaining = this.groups - (first.length + last.length);
571 if (!remaining) {
572 throw new address_error_1.AddressError('Error parsing groups');
573 }
574 this.elidedGroups = remaining;
575 this.elisionBegin = first.length;
576 this.elisionEnd = first.length + this.elidedGroups;
577 groups = groups.concat(first);
578 for (let i = 0; i < remaining; i++) {
579 groups.push('0');
580 }
581 groups = groups.concat(last);
582 }
583 else if (halves.length === 1) {
584 groups = address.split(':');
585 this.elidedGroups = 0;
586 }
587 else {
588 throw new address_error_1.AddressError('Too many :: groups found');
589 }
590 groups = groups.map((group) => parseInt(group, 16).toString(16));
591 if (groups.length !== this.groups) {
592 throw new address_error_1.AddressError('Incorrect number of groups found');
593 }
594 return groups;
595 }
596 /**
597 * Return the canonical form of the address
598 * @memberof Address6
599 * @instance
600 * @returns {String}
601 */
602 canonicalForm() {
603 return this.parsedAddress.map(paddedHex).join(':');
604 }
605 /**
606 * Return the decimal form of the address
607 * @memberof Address6
608 * @instance
609 * @returns {String}
610 */
611 decimal() {
612 return this.parsedAddress.map((n) => parseInt(n, 16).toString(10).padStart(5, '0')).join(':');
613 }
614 /**
615 * Return the address as a BigInt
616 * @memberof Address6
617 * @instance
618 * @returns {bigint}
619 */
620 bigInt() {
621 return BigInt(`0x${this.parsedAddress.map(paddedHex).join('')}`);
622 }
623 /**
624 * Return the last two groups of this address as an IPv4 address string
625 * @memberof Address6
626 * @instance
627 * @returns {Address4}
628 * @example
629 * var address = new Address6('2001:4860:4001::1825:bf11');
630 * address.to4().correctForm(); // '24.37.191.17'
631 */
632 to4() {
633 const binary = this.binaryZeroPad().split('');
634 return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16));
635 }
636 /**
637 * Return the v4-in-v6 form of the address
638 * @memberof Address6
639 * @instance
640 * @returns {String}
641 */
642 to4in6() {
643 const address4 = this.to4();
644 const address6 = new Address6(this.parsedAddress.slice(0, 6).join(':'), 6);
645 const correct = address6.correctForm();
646 let infix = '';
647 if (!/:$/.test(correct)) {
648 infix = ':';
649 }
650 return correct + infix + address4.address;
651 }
652 /**
653 * Return an object containing the Teredo properties of the address
654 * @memberof Address6
655 * @instance
656 * @returns {Object}
657 */
658 inspectTeredo() {
659 /*
660 - Bits 0 to 31 are set to the Teredo prefix (normally 2001:0000::/32).
661 - Bits 32 to 63 embed the primary IPv4 address of the Teredo server that
662 is used.
663 - Bits 64 to 79 can be used to define some flags. Currently only the
664 higher order bit is used; it is set to 1 if the Teredo client is
665 located behind a cone NAT, 0 otherwise. For Microsoft's Windows Vista
666 and Windows Server 2008 implementations, more bits are used. In those
667 implementations, the format for these 16 bits is "CRAAAAUG AAAAAAAA",
668 where "C" remains the "Cone" flag. The "R" bit is reserved for future
669 use. The "U" bit is for the Universal/Local flag (set to 0). The "G" bit
670 is Individual/Group flag (set to 0). The A bits are set to a 12-bit
671 randomly generated number chosen by the Teredo client to introduce
672 additional protection for the Teredo node against IPv6-based scanning
673 attacks.
674 - Bits 80 to 95 contains the obfuscated UDP port number. This is the
675 port number that is mapped by the NAT to the Teredo client with all
676 bits inverted.
677 - Bits 96 to 127 contains the obfuscated IPv4 address. This is the
678 public IPv4 address of the NAT with all bits inverted.
679 */
680 const prefix = this.getBitsBase16(0, 32);
681 const bitsForUdpPort = this.getBits(80, 96);
682 // eslint-disable-next-line no-bitwise
683 const udpPort = (bitsForUdpPort ^ BigInt('0xffff')).toString();
684 const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64));
685 const bitsForClient4 = this.getBits(96, 128);
686 // eslint-disable-next-line no-bitwise
687 const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16));
688 const flagsBase2 = this.getBitsBase2(64, 80);
689 const coneNat = (0, common_1.testBit)(flagsBase2, 15);
690 const reserved = (0, common_1.testBit)(flagsBase2, 14);
691 const groupIndividual = (0, common_1.testBit)(flagsBase2, 8);
692 const universalLocal = (0, common_1.testBit)(flagsBase2, 9);
693 const nonce = BigInt(`0b${flagsBase2.slice(2, 6) + flagsBase2.slice(8, 16)}`).toString(10);
694 return {
695 prefix: `${prefix.slice(0, 4)}:${prefix.slice(4, 8)}`,
696 server4: server4.address,
697 client4: client4.address,
698 flags: flagsBase2,
699 coneNat,
700 microsoft: {
701 reserved,
702 universalLocal,
703 groupIndividual,
704 nonce,
705 },
706 udpPort,
707 };
708 }
709 /**
710 * Return an object containing the 6to4 properties of the address
711 * @memberof Address6
712 * @instance
713 * @returns {Object}
714 */
715 inspect6to4() {
716 /*
717 - Bits 0 to 15 are set to the 6to4 prefix (2002::/16).
718 - Bits 16 to 48 embed the IPv4 address of the 6to4 gateway that is used.
719 */
720 const prefix = this.getBitsBase16(0, 16);
721 const gateway = ipv4_1.Address4.fromHex(this.getBitsBase16(16, 48));
722 return {
723 prefix: prefix.slice(0, 4),
724 gateway: gateway.address,
725 };
726 }
727 /**
728 * Return a v6 6to4 address from a v6 v4inv6 address
729 * @memberof Address6
730 * @instance
731 * @returns {Address6}
732 */
733 to6to4() {
734 if (!this.is4()) {
735 return null;
736 }
737 const addr6to4 = [
738 '2002',
739 this.getBitsBase16(96, 112),
740 this.getBitsBase16(112, 128),
741 '',
742 '/16',
743 ].join(':');
744 return new Address6(addr6to4);
745 }
746 /**
747 * Return a byte array
748 * @memberof Address6
749 * @instance
750 * @returns {Array}
751 */
752 toByteArray() {
753 const valueWithoutPadding = this.bigInt().toString(16);
754 const leadingPad = '0'.repeat(valueWithoutPadding.length % 2);
755 const value = `${leadingPad}${valueWithoutPadding}`;
756 const bytes = [];
757 for (let i = 0, length = value.length; i < length; i += 2) {
758 bytes.push(parseInt(value.substring(i, i + 2), 16));
759 }
760 return bytes;
761 }
762 /**
763 * Return an unsigned byte array
764 * @memberof Address6
765 * @instance
766 * @returns {Array}
767 */
768 toUnsignedByteArray() {
769 return this.toByteArray().map(unsignByte);
770 }
771 /**
772 * Convert a byte array to an Address6 object
773 * @memberof Address6
774 * @static
775 * @returns {Address6}
776 */
777 static fromByteArray(bytes) {
778 return this.fromUnsignedByteArray(bytes.map(unsignByte));
779 }
780 /**
781 * Convert an unsigned byte array to an Address6 object
782 * @memberof Address6
783 * @static
784 * @returns {Address6}
785 */
786 static fromUnsignedByteArray(bytes) {
787 const BYTE_MAX = BigInt('256');
788 let result = BigInt('0');
789 let multiplier = BigInt('1');
790 for (let i = bytes.length - 1; i >= 0; i--) {
791 result += multiplier * BigInt(bytes[i].toString(10));
792 multiplier *= BYTE_MAX;
793 }
794 return Address6.fromBigInt(result);
795 }
796 /**
797 * Returns true if the address is in the canonical form, false otherwise
798 * @memberof Address6
799 * @instance
800 * @returns {boolean}
801 */
802 isCanonical() {
803 return this.addressMinusSuffix === this.canonicalForm();
804 }
805 /**
806 * Returns true if the address is a link local address, false otherwise
807 * @memberof Address6
808 * @instance
809 * @returns {boolean}
810 */
811 isLinkLocal() {
812 // Zeroes are required, i.e. we can't check isInSubnet with 'fe80::/10'
813 if (this.getBitsBase2(0, 64) ===
814 '1111111010000000000000000000000000000000000000000000000000000000') {
815 return true;
816 }
817 return false;
818 }
819 /**
820 * Returns true if the address is a multicast address, false otherwise
821 * @memberof Address6
822 * @instance
823 * @returns {boolean}
824 */
825 isMulticast() {
826 return this.getType() === 'Multicast';
827 }
828 /**
829 * Returns true if the address is a v4-in-v6 address, false otherwise
830 * @memberof Address6
831 * @instance
832 * @returns {boolean}
833 */
834 is4() {
835 return this.v4;
836 }
837 /**
838 * Returns true if the address is a Teredo address, false otherwise
839 * @memberof Address6
840 * @instance
841 * @returns {boolean}
842 */
843 isTeredo() {
844 return this.isInSubnet(new Address6('2001::/32'));
845 }
846 /**
847 * Returns true if the address is a 6to4 address, false otherwise
848 * @memberof Address6
849 * @instance
850 * @returns {boolean}
851 */
852 is6to4() {
853 return this.isInSubnet(new Address6('2002::/16'));
854 }
855 /**
856 * Returns true if the address is a loopback address, false otherwise
857 * @memberof Address6
858 * @instance
859 * @returns {boolean}
860 */
861 isLoopback() {
862 return this.getType() === 'Loopback';
863 }
864 // #endregion
865 // #region HTML
866 /**
867 * @returns {String} the address in link form with a default port of 80
868 */
869 href(optionalPort) {
870 if (optionalPort === undefined) {
871 optionalPort = '';
872 }
873 else {
874 optionalPort = `:${optionalPort}`;
875 }
876 return `http://[${this.correctForm()}]${optionalPort}/`;
877 }
878 /**
879 * @returns {String} a link suitable for conveying the address via a URL hash
880 */
881 link(options) {
882 if (!options) {
883 options = {};
884 }
885 if (options.className === undefined) {
886 options.className = '';
887 }
888 if (options.prefix === undefined) {
889 options.prefix = '/#address=';
890 }
891 if (options.v4 === undefined) {
892 options.v4 = false;
893 }
894 let formFunction = this.correctForm;
895 if (options.v4) {
896 formFunction = this.to4in6;
897 }
898 const form = formFunction.call(this);
899 if (options.className) {
900 return `<a href="${options.prefix}${form}" class="${options.className}">${form}</a>`;
901 }
902 return `<a href="${options.prefix}${form}">${form}</a>`;
903 }
904 /**
905 * Groups an address
906 * @returns {String}
907 */
908 group() {
909 if (this.elidedGroups === 0) {
910 // The simple case
911 return helpers.simpleGroup(this.address).join(':');
912 }
913 assert(typeof this.elidedGroups === 'number');
914 assert(typeof this.elisionBegin === 'number');
915 // The elided case
916 const output = [];
917 const [left, right] = this.address.split('::');
918 if (left.length) {
919 output.push(...helpers.simpleGroup(left));
920 }
921 else {
922 output.push('');
923 }
924 const classes = ['hover-group'];
925 for (let i = this.elisionBegin; i < this.elisionBegin + this.elidedGroups; i++) {
926 classes.push(`group-${i}`);
927 }
928 output.push(`<span class="${classes.join(' ')}"></span>`);
929 if (right.length) {
930 output.push(...helpers.simpleGroup(right, this.elisionEnd));
931 }
932 else {
933 output.push('');
934 }
935 if (this.is4()) {
936 assert(this.address4 instanceof ipv4_1.Address4);
937 output.pop();
938 output.push(this.address4.groupForV6());
939 }
940 return output.join(':');
941 }
942 // #endregion
943 // #region Regular expressions
944 /**
945 * Generate a regular expression string that can be used to find or validate
946 * all variations of this address
947 * @memberof Address6
948 * @instance
949 * @param {boolean} substringSearch
950 * @returns {string}
951 */
952 regularExpressionString(substringSearch = false) {
953 let output = [];
954 // TODO: revisit why this is necessary
955 const address6 = new Address6(this.correctForm());
956 if (address6.elidedGroups === 0) {
957 // The simple case
958 output.push((0, regular_expressions_1.simpleRegularExpression)(address6.parsedAddress));
959 }
960 else if (address6.elidedGroups === constants6.GROUPS) {
961 // A completely elided address
962 output.push((0, regular_expressions_1.possibleElisions)(constants6.GROUPS));
963 }
964 else {
965 // A partially elided address
966 const halves = address6.address.split('::');
967 if (halves[0].length) {
968 output.push((0, regular_expressions_1.simpleRegularExpression)(halves[0].split(':')));
969 }
970 assert(typeof address6.elidedGroups === 'number');
971 output.push((0, regular_expressions_1.possibleElisions)(address6.elidedGroups, halves[0].length !== 0, halves[1].length !== 0));
972 if (halves[1].length) {
973 output.push((0, regular_expressions_1.simpleRegularExpression)(halves[1].split(':')));
974 }
975 output = [output.join(':')];
976 }
977 if (!substringSearch) {
978 output = [
979 '(?=^|',
980 regular_expressions_1.ADDRESS_BOUNDARY,
981 '|[^\\w\\:])(',
982 ...output,
983 ')(?=[^\\w\\:]|',
984 regular_expressions_1.ADDRESS_BOUNDARY,
985 '|$)',
986 ];
987 }
988 return output.join('');
989 }
990 /**
991 * Generate a regular expression that can be used to find or validate all
992 * variations of this address.
993 * @memberof Address6
994 * @instance
995 * @param {boolean} substringSearch
996 * @returns {RegExp}
997 */
998 regularExpression(substringSearch = false) {
999 return new RegExp(this.regularExpressionString(substringSearch), 'i');
1000 }
1001}
1002exports.Address6 = Address6;
1003//# sourceMappingURL=ipv6.js.map
Note: See TracBrowser for help on using the repository browser.