@ttmg/cli 0.3.8-beta.2 → 0.3.8-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +748 -292
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -584,17 +584,17 @@ var hasRequiredBrowser;
|
|
|
584
584
|
function requireBrowser () {
|
|
585
585
|
if (hasRequiredBrowser) return browser.exports;
|
|
586
586
|
hasRequiredBrowser = 1;
|
|
587
|
-
(function (module, exports
|
|
587
|
+
(function (module, exports) {
|
|
588
588
|
/**
|
|
589
589
|
* This is the web browser implementation of `debug()`.
|
|
590
590
|
*/
|
|
591
591
|
|
|
592
|
-
exports
|
|
593
|
-
exports
|
|
594
|
-
exports
|
|
595
|
-
exports
|
|
596
|
-
exports
|
|
597
|
-
exports
|
|
592
|
+
exports.formatArgs = formatArgs;
|
|
593
|
+
exports.save = save;
|
|
594
|
+
exports.load = load;
|
|
595
|
+
exports.useColors = useColors;
|
|
596
|
+
exports.storage = localstorage();
|
|
597
|
+
exports.destroy = (() => {
|
|
598
598
|
let warned = false;
|
|
599
599
|
|
|
600
600
|
return () => {
|
|
@@ -609,7 +609,7 @@ function requireBrowser () {
|
|
|
609
609
|
* Colors.
|
|
610
610
|
*/
|
|
611
611
|
|
|
612
|
-
exports
|
|
612
|
+
exports.colors = [
|
|
613
613
|
'#0000CC',
|
|
614
614
|
'#0000FF',
|
|
615
615
|
'#0033CC',
|
|
@@ -774,7 +774,7 @@ function requireBrowser () {
|
|
|
774
774
|
*
|
|
775
775
|
* @api public
|
|
776
776
|
*/
|
|
777
|
-
exports
|
|
777
|
+
exports.log = console.debug || console.log || (() => {});
|
|
778
778
|
|
|
779
779
|
/**
|
|
780
780
|
* Save `namespaces`.
|
|
@@ -785,9 +785,9 @@ function requireBrowser () {
|
|
|
785
785
|
function save(namespaces) {
|
|
786
786
|
try {
|
|
787
787
|
if (namespaces) {
|
|
788
|
-
exports
|
|
788
|
+
exports.storage.setItem('debug', namespaces);
|
|
789
789
|
} else {
|
|
790
|
-
exports
|
|
790
|
+
exports.storage.removeItem('debug');
|
|
791
791
|
}
|
|
792
792
|
} catch (error) {
|
|
793
793
|
// Swallow
|
|
@@ -804,7 +804,7 @@ function requireBrowser () {
|
|
|
804
804
|
function load() {
|
|
805
805
|
let r;
|
|
806
806
|
try {
|
|
807
|
-
r = exports
|
|
807
|
+
r = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG') ;
|
|
808
808
|
} catch (error) {
|
|
809
809
|
// Swallow
|
|
810
810
|
// XXX (@Qix-) should we be logging these?
|
|
@@ -840,7 +840,7 @@ function requireBrowser () {
|
|
|
840
840
|
}
|
|
841
841
|
}
|
|
842
842
|
|
|
843
|
-
module.exports = requireCommon$1()(exports
|
|
843
|
+
module.exports = requireCommon$1()(exports);
|
|
844
844
|
|
|
845
845
|
const {formatters} = module.exports;
|
|
846
846
|
|
|
@@ -1029,7 +1029,7 @@ var hasRequiredNode;
|
|
|
1029
1029
|
function requireNode () {
|
|
1030
1030
|
if (hasRequiredNode) return node.exports;
|
|
1031
1031
|
hasRequiredNode = 1;
|
|
1032
|
-
(function (module, exports
|
|
1032
|
+
(function (module, exports) {
|
|
1033
1033
|
const tty = require$$1;
|
|
1034
1034
|
const util = require$$1$1;
|
|
1035
1035
|
|
|
@@ -1037,13 +1037,13 @@ function requireNode () {
|
|
|
1037
1037
|
* This is the Node.js implementation of `debug()`.
|
|
1038
1038
|
*/
|
|
1039
1039
|
|
|
1040
|
-
exports
|
|
1041
|
-
exports
|
|
1042
|
-
exports
|
|
1043
|
-
exports
|
|
1044
|
-
exports
|
|
1045
|
-
exports
|
|
1046
|
-
exports
|
|
1040
|
+
exports.init = init;
|
|
1041
|
+
exports.log = log;
|
|
1042
|
+
exports.formatArgs = formatArgs;
|
|
1043
|
+
exports.save = save;
|
|
1044
|
+
exports.load = load;
|
|
1045
|
+
exports.useColors = useColors;
|
|
1046
|
+
exports.destroy = util.deprecate(
|
|
1047
1047
|
() => {},
|
|
1048
1048
|
'Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'
|
|
1049
1049
|
);
|
|
@@ -1052,7 +1052,7 @@ function requireNode () {
|
|
|
1052
1052
|
* Colors.
|
|
1053
1053
|
*/
|
|
1054
1054
|
|
|
1055
|
-
exports
|
|
1055
|
+
exports.colors = [6, 2, 3, 4, 5, 1];
|
|
1056
1056
|
|
|
1057
1057
|
try {
|
|
1058
1058
|
// Optional dependency (as in, doesn't need to be installed, NOT like optionalDependencies in package.json)
|
|
@@ -1060,7 +1060,7 @@ function requireNode () {
|
|
|
1060
1060
|
const supportsColor = requireSupportsColor();
|
|
1061
1061
|
|
|
1062
1062
|
if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {
|
|
1063
|
-
exports
|
|
1063
|
+
exports.colors = [
|
|
1064
1064
|
20,
|
|
1065
1065
|
21,
|
|
1066
1066
|
26,
|
|
@@ -1149,7 +1149,7 @@ function requireNode () {
|
|
|
1149
1149
|
* $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
|
|
1150
1150
|
*/
|
|
1151
1151
|
|
|
1152
|
-
exports
|
|
1152
|
+
exports.inspectOpts = Object.keys(process.env).filter(key => {
|
|
1153
1153
|
return /^debug_/i.test(key);
|
|
1154
1154
|
}).reduce((obj, key) => {
|
|
1155
1155
|
// Camel-case
|
|
@@ -1181,8 +1181,8 @@ function requireNode () {
|
|
|
1181
1181
|
*/
|
|
1182
1182
|
|
|
1183
1183
|
function useColors() {
|
|
1184
|
-
return 'colors' in exports
|
|
1185
|
-
Boolean(exports
|
|
1184
|
+
return 'colors' in exports.inspectOpts ?
|
|
1185
|
+
Boolean(exports.inspectOpts.colors) :
|
|
1186
1186
|
tty.isatty(process.stderr.fd);
|
|
1187
1187
|
}
|
|
1188
1188
|
|
|
@@ -1208,7 +1208,7 @@ function requireNode () {
|
|
|
1208
1208
|
}
|
|
1209
1209
|
|
|
1210
1210
|
function getDate() {
|
|
1211
|
-
if (exports
|
|
1211
|
+
if (exports.inspectOpts.hideDate) {
|
|
1212
1212
|
return '';
|
|
1213
1213
|
}
|
|
1214
1214
|
return new Date().toISOString() + ' ';
|
|
@@ -1219,7 +1219,7 @@ function requireNode () {
|
|
|
1219
1219
|
*/
|
|
1220
1220
|
|
|
1221
1221
|
function log(...args) {
|
|
1222
|
-
return process.stderr.write(util.formatWithOptions(exports
|
|
1222
|
+
return process.stderr.write(util.formatWithOptions(exports.inspectOpts, ...args) + '\n');
|
|
1223
1223
|
}
|
|
1224
1224
|
|
|
1225
1225
|
/**
|
|
@@ -1259,13 +1259,13 @@ function requireNode () {
|
|
|
1259
1259
|
function init(debug) {
|
|
1260
1260
|
debug.inspectOpts = {};
|
|
1261
1261
|
|
|
1262
|
-
const keys = Object.keys(exports
|
|
1262
|
+
const keys = Object.keys(exports.inspectOpts);
|
|
1263
1263
|
for (let i = 0; i < keys.length; i++) {
|
|
1264
|
-
debug.inspectOpts[keys[i]] = exports
|
|
1264
|
+
debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
|
|
1265
1265
|
}
|
|
1266
1266
|
}
|
|
1267
1267
|
|
|
1268
|
-
module.exports = requireCommon$1()(exports
|
|
1268
|
+
module.exports = requireCommon$1()(exports);
|
|
1269
1269
|
|
|
1270
1270
|
const {formatters} = module.exports;
|
|
1271
1271
|
|
|
@@ -3354,6 +3354,27 @@ var ipv4 = {};
|
|
|
3354
3354
|
|
|
3355
3355
|
var common = {};
|
|
3356
3356
|
|
|
3357
|
+
var addressError = {};
|
|
3358
|
+
|
|
3359
|
+
var hasRequiredAddressError;
|
|
3360
|
+
|
|
3361
|
+
function requireAddressError () {
|
|
3362
|
+
if (hasRequiredAddressError) return addressError;
|
|
3363
|
+
hasRequiredAddressError = 1;
|
|
3364
|
+
Object.defineProperty(addressError, "__esModule", { value: true });
|
|
3365
|
+
addressError.AddressError = void 0;
|
|
3366
|
+
class AddressError extends Error {
|
|
3367
|
+
constructor(message, parseMessage) {
|
|
3368
|
+
super(message);
|
|
3369
|
+
this.name = 'AddressError';
|
|
3370
|
+
this.parseMessage = parseMessage;
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
addressError.AddressError = AddressError;
|
|
3374
|
+
|
|
3375
|
+
return addressError;
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3357
3378
|
var hasRequiredCommon;
|
|
3358
3379
|
|
|
3359
3380
|
function requireCommon () {
|
|
@@ -3362,9 +3383,11 @@ function requireCommon () {
|
|
|
3362
3383
|
Object.defineProperty(common, "__esModule", { value: true });
|
|
3363
3384
|
common.isInSubnet = isInSubnet;
|
|
3364
3385
|
common.isCorrect = isCorrect;
|
|
3386
|
+
common.prefixLengthFromMask = prefixLengthFromMask;
|
|
3365
3387
|
common.numberToPaddedHex = numberToPaddedHex;
|
|
3366
3388
|
common.stringToPaddedHex = stringToPaddedHex;
|
|
3367
3389
|
common.testBit = testBit;
|
|
3390
|
+
const address_error_1 = /*@__PURE__*/ requireAddressError();
|
|
3368
3391
|
function isInSubnet(address) {
|
|
3369
3392
|
if (this.subnetMask < address.subnetMask) {
|
|
3370
3393
|
return false;
|
|
@@ -3385,6 +3408,25 @@ function requireCommon () {
|
|
|
3385
3408
|
return this.parsedSubnet === String(this.subnetMask);
|
|
3386
3409
|
};
|
|
3387
3410
|
}
|
|
3411
|
+
/**
|
|
3412
|
+
* Returns the prefix length (number of leading 1 bits) of a contiguous
|
|
3413
|
+
* subnet mask. Throws `AddressError` if the mask is non-contiguous (e.g.
|
|
3414
|
+
* `255.0.255.0`).
|
|
3415
|
+
*/
|
|
3416
|
+
function prefixLengthFromMask(value, totalBits) {
|
|
3417
|
+
const binary = value.toString(2).padStart(totalBits, '0');
|
|
3418
|
+
if (binary.length > totalBits) {
|
|
3419
|
+
throw new address_error_1.AddressError('Invalid subnet mask.');
|
|
3420
|
+
}
|
|
3421
|
+
const firstZero = binary.indexOf('0');
|
|
3422
|
+
if (firstZero === -1) {
|
|
3423
|
+
return totalBits;
|
|
3424
|
+
}
|
|
3425
|
+
if (binary.slice(firstZero).includes('1')) {
|
|
3426
|
+
throw new address_error_1.AddressError('Invalid subnet mask.');
|
|
3427
|
+
}
|
|
3428
|
+
return firstZero;
|
|
3429
|
+
}
|
|
3388
3430
|
function numberToPaddedHex(number) {
|
|
3389
3431
|
return number.toString(16).padStart(2, '0');
|
|
3390
3432
|
}
|
|
@@ -3424,27 +3466,6 @@ function requireConstants$1 () {
|
|
|
3424
3466
|
return constants$1;
|
|
3425
3467
|
}
|
|
3426
3468
|
|
|
3427
|
-
var addressError = {};
|
|
3428
|
-
|
|
3429
|
-
var hasRequiredAddressError;
|
|
3430
|
-
|
|
3431
|
-
function requireAddressError () {
|
|
3432
|
-
if (hasRequiredAddressError) return addressError;
|
|
3433
|
-
hasRequiredAddressError = 1;
|
|
3434
|
-
Object.defineProperty(addressError, "__esModule", { value: true });
|
|
3435
|
-
addressError.AddressError = void 0;
|
|
3436
|
-
class AddressError extends Error {
|
|
3437
|
-
constructor(message, parseMessage) {
|
|
3438
|
-
super(message);
|
|
3439
|
-
this.name = 'AddressError';
|
|
3440
|
-
this.parseMessage = parseMessage;
|
|
3441
|
-
}
|
|
3442
|
-
}
|
|
3443
|
-
addressError.AddressError = AddressError;
|
|
3444
|
-
|
|
3445
|
-
return addressError;
|
|
3446
|
-
}
|
|
3447
|
-
|
|
3448
3469
|
var hasRequiredIpv4;
|
|
3449
3470
|
|
|
3450
3471
|
function requireIpv4 () {
|
|
@@ -3476,12 +3497,12 @@ function requireIpv4 () {
|
|
|
3476
3497
|
};
|
|
3477
3498
|
Object.defineProperty(ipv4, "__esModule", { value: true });
|
|
3478
3499
|
ipv4.Address4 = void 0;
|
|
3479
|
-
const common = __importStar(requireCommon());
|
|
3480
|
-
const constants = __importStar(requireConstants$1());
|
|
3481
|
-
const address_error_1 = requireAddressError();
|
|
3500
|
+
const common = __importStar(/*@__PURE__*/ requireCommon());
|
|
3501
|
+
const constants = __importStar(/*@__PURE__*/ requireConstants$1());
|
|
3502
|
+
const address_error_1 = /*@__PURE__*/ requireAddressError();
|
|
3503
|
+
const isCorrect4 = common.isCorrect(constants.BITS);
|
|
3482
3504
|
/**
|
|
3483
3505
|
* Represents an IPv4 address
|
|
3484
|
-
* @class Address4
|
|
3485
3506
|
* @param {string} address - An IPv4 address string
|
|
3486
3507
|
*/
|
|
3487
3508
|
class Address4 {
|
|
@@ -3494,15 +3515,11 @@ function requireIpv4 () {
|
|
|
3494
3515
|
this.v4 = true;
|
|
3495
3516
|
/**
|
|
3496
3517
|
* Returns true if the address is correct, false otherwise
|
|
3497
|
-
* @memberof Address4
|
|
3498
|
-
* @instance
|
|
3499
3518
|
* @returns {Boolean}
|
|
3500
3519
|
*/
|
|
3501
|
-
this.isCorrect =
|
|
3520
|
+
this.isCorrect = isCorrect4;
|
|
3502
3521
|
/**
|
|
3503
3522
|
* Returns true if the given address is in the subnet of the current address
|
|
3504
|
-
* @memberof Address4
|
|
3505
|
-
* @instance
|
|
3506
3523
|
* @returns {boolean}
|
|
3507
3524
|
*/
|
|
3508
3525
|
this.isInSubnet = common.isInSubnet;
|
|
@@ -3520,6 +3537,13 @@ function requireIpv4 () {
|
|
|
3520
3537
|
this.addressMinusSuffix = address;
|
|
3521
3538
|
this.parsedAddress = this.parse(address);
|
|
3522
3539
|
}
|
|
3540
|
+
/**
|
|
3541
|
+
* Returns true if the given string is a valid IPv4 address (with optional
|
|
3542
|
+
* CIDR subnet), false otherwise. Host bits in the subnet portion are
|
|
3543
|
+
* allowed (e.g. `192.168.1.5/24` is valid); for strict network-address
|
|
3544
|
+
* validation compare `correctForm()` to `startAddress().correctForm()`,
|
|
3545
|
+
* or use `networkForm()`.
|
|
3546
|
+
*/
|
|
3523
3547
|
static isValid(address) {
|
|
3524
3548
|
try {
|
|
3525
3549
|
// eslint-disable-next-line no-new
|
|
@@ -3530,8 +3554,11 @@ function requireIpv4 () {
|
|
|
3530
3554
|
return false;
|
|
3531
3555
|
}
|
|
3532
3556
|
}
|
|
3533
|
-
|
|
3534
|
-
* Parses
|
|
3557
|
+
/**
|
|
3558
|
+
* Parses an IPv4 address string into its four octet groups and stores the
|
|
3559
|
+
* result on `this.parsedAddress`. Called automatically by the constructor;
|
|
3560
|
+
* you typically don't need to call it directly. Throws `AddressError` if
|
|
3561
|
+
* the input is not a valid IPv4 address.
|
|
3535
3562
|
*/
|
|
3536
3563
|
parse(address) {
|
|
3537
3564
|
const groups = address.split('.');
|
|
@@ -3541,45 +3568,110 @@ function requireIpv4 () {
|
|
|
3541
3568
|
return groups;
|
|
3542
3569
|
}
|
|
3543
3570
|
/**
|
|
3544
|
-
* Returns the correct form
|
|
3545
|
-
*
|
|
3546
|
-
*
|
|
3547
|
-
* @returns {String}
|
|
3571
|
+
* Returns the address in correct form: octets joined with `.` and any
|
|
3572
|
+
* leading zeros stripped (e.g. `192.168.1.1`). For IPv4 this matches the
|
|
3573
|
+
* canonical dotted-decimal representation.
|
|
3548
3574
|
*/
|
|
3549
3575
|
correctForm() {
|
|
3550
3576
|
return this.parsedAddress.map((part) => parseInt(part, 10)).join('.');
|
|
3551
3577
|
}
|
|
3552
3578
|
/**
|
|
3553
|
-
*
|
|
3554
|
-
*
|
|
3555
|
-
*
|
|
3579
|
+
* Construct an `Address4` from an address and a dotted-decimal subnet
|
|
3580
|
+
* mask given as separate strings (e.g. as returned by Node's
|
|
3581
|
+
* `os.networkInterfaces()`). Throws `AddressError` if the mask is
|
|
3582
|
+
* non-contiguous (e.g. `255.0.255.0`).
|
|
3583
|
+
* @example
|
|
3584
|
+
* var address = Address4.fromAddressAndMask('192.168.1.1', '255.255.255.0');
|
|
3585
|
+
* address.subnetMask; // 24
|
|
3586
|
+
*/
|
|
3587
|
+
static fromAddressAndMask(address, mask) {
|
|
3588
|
+
const bits = common.prefixLengthFromMask(new Address4(mask).bigInt(), constants.BITS);
|
|
3589
|
+
return new Address4(`${address}/${bits}`);
|
|
3590
|
+
}
|
|
3591
|
+
/**
|
|
3592
|
+
* Construct an `Address4` from an address and a Cisco-style wildcard mask
|
|
3593
|
+
* given as separate strings (e.g. `0.0.0.255` for a `/24`). The wildcard
|
|
3594
|
+
* mask is the bitwise inverse of the subnet mask. Throws `AddressError`
|
|
3595
|
+
* if the mask is non-contiguous (e.g. `0.255.0.255`).
|
|
3596
|
+
* @example
|
|
3597
|
+
* var address = Address4.fromAddressAndWildcardMask('10.0.0.1', '0.0.0.255');
|
|
3598
|
+
* address.subnetMask; // 24
|
|
3599
|
+
*/
|
|
3600
|
+
static fromAddressAndWildcardMask(address, wildcardMask) {
|
|
3601
|
+
const wildcard = new Address4(wildcardMask).bigInt();
|
|
3602
|
+
const allOnes = (BigInt(1) << BigInt(constants.BITS)) - BigInt(1);
|
|
3603
|
+
// eslint-disable-next-line no-bitwise
|
|
3604
|
+
const mask = wildcard ^ allOnes;
|
|
3605
|
+
const bits = common.prefixLengthFromMask(mask, constants.BITS);
|
|
3606
|
+
return new Address4(`${address}/${bits}`);
|
|
3607
|
+
}
|
|
3608
|
+
/**
|
|
3609
|
+
* Construct an `Address4` from a wildcard pattern with trailing `*`
|
|
3610
|
+
* octets. The number of trailing wildcards determines the prefix
|
|
3611
|
+
* length: each `*` represents 8 bits.
|
|
3612
|
+
*
|
|
3613
|
+
* Only trailing whole-octet wildcards are supported. Partial-octet
|
|
3614
|
+
* wildcards (e.g. `192.168.0.1*`) and interior wildcards (e.g.
|
|
3615
|
+
* `192.*.0.1`) throw `AddressError`.
|
|
3616
|
+
* @example
|
|
3617
|
+
* Address4.fromWildcard('192.168.0.*').subnet; // '/24'
|
|
3618
|
+
* Address4.fromWildcard('192.168.*.*').subnet; // '/16'
|
|
3619
|
+
* Address4.fromWildcard('*.*.*.*').subnet; // '/0'
|
|
3620
|
+
*/
|
|
3621
|
+
static fromWildcard(input) {
|
|
3622
|
+
const groups = input.split('.');
|
|
3623
|
+
if (groups.length !== constants.GROUPS) {
|
|
3624
|
+
throw new address_error_1.AddressError('Wildcard pattern must have 4 octets');
|
|
3625
|
+
}
|
|
3626
|
+
let firstWildcard = -1;
|
|
3627
|
+
for (let i = 0; i < groups.length; i++) {
|
|
3628
|
+
if (groups[i] === '*') {
|
|
3629
|
+
if (firstWildcard === -1) {
|
|
3630
|
+
firstWildcard = i;
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
else if (firstWildcard !== -1) {
|
|
3634
|
+
throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing octets (e.g. `192.168.0.*`)');
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
|
|
3638
|
+
const replaced = groups.map((g) => (g === '*' ? '0' : g));
|
|
3639
|
+
const subnetBits = constants.BITS - trailing * 8;
|
|
3640
|
+
return new Address4(`${replaced.join('.')}/${subnetBits}`);
|
|
3641
|
+
}
|
|
3642
|
+
/**
|
|
3643
|
+
* Converts a hex string to an IPv4 address object. Accepts 8 hex digits
|
|
3644
|
+
* with optional `:` separators (e.g. `'7f000001'` or `'7f:00:00:01'`).
|
|
3645
|
+
* Throws `AddressError` for any other length or for non-hex characters.
|
|
3556
3646
|
* @param {string} hex - a hex string to convert
|
|
3557
3647
|
* @returns {Address4}
|
|
3558
3648
|
*/
|
|
3559
3649
|
static fromHex(hex) {
|
|
3560
|
-
const
|
|
3650
|
+
const stripped = hex.replace(/:/g, '');
|
|
3651
|
+
if (!/^[0-9a-fA-F]{8}$/.test(stripped)) {
|
|
3652
|
+
throw new address_error_1.AddressError('IPv4 hex must be exactly 8 hex digits');
|
|
3653
|
+
}
|
|
3561
3654
|
const groups = [];
|
|
3562
|
-
let i;
|
|
3563
|
-
|
|
3564
|
-
const h = padded.slice(i, i + 2);
|
|
3565
|
-
groups.push(parseInt(h, 16));
|
|
3655
|
+
for (let i = 0; i < 8; i += 2) {
|
|
3656
|
+
groups.push(parseInt(stripped.slice(i, i + 2), 16));
|
|
3566
3657
|
}
|
|
3567
3658
|
return new Address4(groups.join('.'));
|
|
3568
3659
|
}
|
|
3569
3660
|
/**
|
|
3570
|
-
* Converts an integer into a IPv4 address object
|
|
3571
|
-
*
|
|
3572
|
-
*
|
|
3661
|
+
* Converts an integer into a IPv4 address object. The integer must be a
|
|
3662
|
+
* non-negative safe integer in the range `[0, 2**32 - 1]`; otherwise
|
|
3663
|
+
* `AddressError` is thrown.
|
|
3573
3664
|
* @param {integer} integer - a number to convert
|
|
3574
3665
|
* @returns {Address4}
|
|
3575
3666
|
*/
|
|
3576
3667
|
static fromInteger(integer) {
|
|
3577
|
-
|
|
3668
|
+
if (!Number.isInteger(integer) || integer < 0 || integer > 0xffffffff) {
|
|
3669
|
+
throw new address_error_1.AddressError('IPv4 integer must be in the range 0 to 2**32 - 1');
|
|
3670
|
+
}
|
|
3671
|
+
return Address4.fromHex(integer.toString(16).padStart(8, '0'));
|
|
3578
3672
|
}
|
|
3579
3673
|
/**
|
|
3580
3674
|
* Return an address from in-addr.arpa form
|
|
3581
|
-
* @memberof Address4
|
|
3582
|
-
* @static
|
|
3583
3675
|
* @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
|
|
3584
3676
|
* @returns {Adress4}
|
|
3585
3677
|
* @example
|
|
@@ -3594,17 +3686,15 @@ function requireIpv4 () {
|
|
|
3594
3686
|
}
|
|
3595
3687
|
/**
|
|
3596
3688
|
* Converts an IPv4 address object to a hex string
|
|
3597
|
-
* @memberof Address4
|
|
3598
|
-
* @instance
|
|
3599
3689
|
* @returns {String}
|
|
3600
3690
|
*/
|
|
3601
3691
|
toHex() {
|
|
3602
3692
|
return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(':');
|
|
3603
3693
|
}
|
|
3604
3694
|
/**
|
|
3605
|
-
* Converts an IPv4 address object to an array of bytes
|
|
3606
|
-
*
|
|
3607
|
-
*
|
|
3695
|
+
* Converts an IPv4 address object to an array of bytes.
|
|
3696
|
+
*
|
|
3697
|
+
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`.
|
|
3608
3698
|
* @returns {Array}
|
|
3609
3699
|
*/
|
|
3610
3700
|
toArray() {
|
|
@@ -3612,8 +3702,6 @@ function requireIpv4 () {
|
|
|
3612
3702
|
}
|
|
3613
3703
|
/**
|
|
3614
3704
|
* Converts an IPv4 address object to an IPv6 address group
|
|
3615
|
-
* @memberof Address4
|
|
3616
|
-
* @instance
|
|
3617
3705
|
* @returns {String}
|
|
3618
3706
|
*/
|
|
3619
3707
|
toGroup6() {
|
|
@@ -3626,8 +3714,6 @@ function requireIpv4 () {
|
|
|
3626
3714
|
}
|
|
3627
3715
|
/**
|
|
3628
3716
|
* Returns the address as a `bigint`
|
|
3629
|
-
* @memberof Address4
|
|
3630
|
-
* @instance
|
|
3631
3717
|
* @returns {bigint}
|
|
3632
3718
|
*/
|
|
3633
3719
|
bigInt() {
|
|
@@ -3635,8 +3721,6 @@ function requireIpv4 () {
|
|
|
3635
3721
|
}
|
|
3636
3722
|
/**
|
|
3637
3723
|
* Helper function getting start address.
|
|
3638
|
-
* @memberof Address4
|
|
3639
|
-
* @instance
|
|
3640
3724
|
* @returns {bigint}
|
|
3641
3725
|
*/
|
|
3642
3726
|
_startAddress() {
|
|
@@ -3645,8 +3729,6 @@ function requireIpv4 () {
|
|
|
3645
3729
|
/**
|
|
3646
3730
|
* The first address in the range given by this address' subnet.
|
|
3647
3731
|
* Often referred to as the Network Address.
|
|
3648
|
-
* @memberof Address4
|
|
3649
|
-
* @instance
|
|
3650
3732
|
* @returns {Address4}
|
|
3651
3733
|
*/
|
|
3652
3734
|
startAddress() {
|
|
@@ -3655,8 +3737,6 @@ function requireIpv4 () {
|
|
|
3655
3737
|
/**
|
|
3656
3738
|
* The first host address in the range given by this address's subnet ie
|
|
3657
3739
|
* the first address after the Network Address
|
|
3658
|
-
* @memberof Address4
|
|
3659
|
-
* @instance
|
|
3660
3740
|
* @returns {Address4}
|
|
3661
3741
|
*/
|
|
3662
3742
|
startAddressExclusive() {
|
|
@@ -3665,8 +3745,6 @@ function requireIpv4 () {
|
|
|
3665
3745
|
}
|
|
3666
3746
|
/**
|
|
3667
3747
|
* Helper function getting end address.
|
|
3668
|
-
* @memberof Address4
|
|
3669
|
-
* @instance
|
|
3670
3748
|
* @returns {bigint}
|
|
3671
3749
|
*/
|
|
3672
3750
|
_endAddress() {
|
|
@@ -3675,8 +3753,6 @@ function requireIpv4 () {
|
|
|
3675
3753
|
/**
|
|
3676
3754
|
* The last address in the range given by this address' subnet
|
|
3677
3755
|
* Often referred to as the Broadcast
|
|
3678
|
-
* @memberof Address4
|
|
3679
|
-
* @instance
|
|
3680
3756
|
* @returns {Address4}
|
|
3681
3757
|
*/
|
|
3682
3758
|
endAddress() {
|
|
@@ -3685,8 +3761,6 @@ function requireIpv4 () {
|
|
|
3685
3761
|
/**
|
|
3686
3762
|
* The last host address in the range given by this address's subnet ie
|
|
3687
3763
|
* the last address prior to the Broadcast Address
|
|
3688
|
-
* @memberof Address4
|
|
3689
|
-
* @instance
|
|
3690
3764
|
* @returns {Address4}
|
|
3691
3765
|
*/
|
|
3692
3766
|
endAddressExclusive() {
|
|
@@ -3694,19 +3768,47 @@ function requireIpv4 () {
|
|
|
3694
3768
|
return Address4.fromBigInt(this._endAddress() - adjust);
|
|
3695
3769
|
}
|
|
3696
3770
|
/**
|
|
3697
|
-
*
|
|
3698
|
-
*
|
|
3699
|
-
* @
|
|
3771
|
+
* The dotted-decimal form of the subnet mask, e.g. `255.255.240.0` for
|
|
3772
|
+
* a `/20`. Returns an `Address4`; call `.correctForm()` for the string.
|
|
3773
|
+
* @returns {Address4}
|
|
3774
|
+
*/
|
|
3775
|
+
subnetMaskAddress() {
|
|
3776
|
+
return Address4.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants.BITS - this.subnetMask)}`));
|
|
3777
|
+
}
|
|
3778
|
+
/**
|
|
3779
|
+
* The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is
|
|
3780
|
+
* the bitwise inverse of `subnetMaskAddress()`. Returns an `Address4`;
|
|
3781
|
+
* call `.correctForm()` for the string.
|
|
3782
|
+
* @returns {Address4}
|
|
3783
|
+
*/
|
|
3784
|
+
wildcardMask() {
|
|
3785
|
+
return Address4.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants.BITS - this.subnetMask)}`));
|
|
3786
|
+
}
|
|
3787
|
+
/**
|
|
3788
|
+
* The network address in CIDR string form, e.g. `192.168.1.0/24` for
|
|
3789
|
+
* `192.168.1.5/24`. For an address with no explicit subnet the prefix is
|
|
3790
|
+
* `/32`, e.g. `networkForm()` on `192.168.1.5` returns `192.168.1.5/32`.
|
|
3791
|
+
* @returns {string}
|
|
3792
|
+
*/
|
|
3793
|
+
networkForm() {
|
|
3794
|
+
return `${this.startAddress().correctForm()}/${this.subnetMask}`;
|
|
3795
|
+
}
|
|
3796
|
+
/**
|
|
3797
|
+
* Converts a BigInt to a v4 address object. The value must be in the
|
|
3798
|
+
* range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown.
|
|
3700
3799
|
* @param {bigint} bigInt - a BigInt to convert
|
|
3701
3800
|
* @returns {Address4}
|
|
3702
3801
|
*/
|
|
3703
3802
|
static fromBigInt(bigInt) {
|
|
3704
|
-
|
|
3803
|
+
if (bigInt < 0n || bigInt > 0xffffffffn) {
|
|
3804
|
+
throw new address_error_1.AddressError('IPv4 BigInt must be in the range 0 to 2**32 - 1');
|
|
3805
|
+
}
|
|
3806
|
+
return Address4.fromHex(bigInt.toString(16).padStart(8, '0'));
|
|
3705
3807
|
}
|
|
3706
3808
|
/**
|
|
3707
|
-
* Convert a byte array to an Address4 object
|
|
3708
|
-
*
|
|
3709
|
-
*
|
|
3809
|
+
* Convert a byte array to an Address4 object.
|
|
3810
|
+
*
|
|
3811
|
+
* To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`.
|
|
3710
3812
|
* @param {Array<number>} bytes - an array of 4 bytes (0-255)
|
|
3711
3813
|
* @returns {Address4}
|
|
3712
3814
|
*/
|
|
@@ -3724,8 +3826,6 @@ function requireIpv4 () {
|
|
|
3724
3826
|
}
|
|
3725
3827
|
/**
|
|
3726
3828
|
* Convert an unsigned byte array to an Address4 object
|
|
3727
|
-
* @memberof Address4
|
|
3728
|
-
* @static
|
|
3729
3829
|
* @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
|
|
3730
3830
|
* @returns {Address4}
|
|
3731
3831
|
*/
|
|
@@ -3739,8 +3839,6 @@ function requireIpv4 () {
|
|
|
3739
3839
|
/**
|
|
3740
3840
|
* Returns the first n bits of the address, defaulting to the
|
|
3741
3841
|
* subnet mask
|
|
3742
|
-
* @memberof Address4
|
|
3743
|
-
* @instance
|
|
3744
3842
|
* @returns {String}
|
|
3745
3843
|
*/
|
|
3746
3844
|
mask(mask) {
|
|
@@ -3751,8 +3849,6 @@ function requireIpv4 () {
|
|
|
3751
3849
|
}
|
|
3752
3850
|
/**
|
|
3753
3851
|
* Returns the bits in the given range as a base-2 string
|
|
3754
|
-
* @memberof Address4
|
|
3755
|
-
* @instance
|
|
3756
3852
|
* @returns {string}
|
|
3757
3853
|
*/
|
|
3758
3854
|
getBitsBase2(start, end) {
|
|
@@ -3760,10 +3856,8 @@ function requireIpv4 () {
|
|
|
3760
3856
|
}
|
|
3761
3857
|
/**
|
|
3762
3858
|
* Return the reversed ip6.arpa form of the address
|
|
3763
|
-
* @memberof Address4
|
|
3764
3859
|
* @param {Object} options
|
|
3765
3860
|
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
|
|
3766
|
-
* @instance
|
|
3767
3861
|
* @returns {String}
|
|
3768
3862
|
*/
|
|
3769
3863
|
reverseForm(options) {
|
|
@@ -3778,21 +3872,62 @@ function requireIpv4 () {
|
|
|
3778
3872
|
}
|
|
3779
3873
|
/**
|
|
3780
3874
|
* Returns true if the given address is a multicast address
|
|
3781
|
-
* @memberof Address4
|
|
3782
|
-
* @instance
|
|
3783
3875
|
* @returns {boolean}
|
|
3784
3876
|
*/
|
|
3785
3877
|
isMulticast() {
|
|
3786
|
-
return this.isInSubnet(
|
|
3878
|
+
return this.isInSubnet(MULTICAST_V4);
|
|
3879
|
+
}
|
|
3880
|
+
/**
|
|
3881
|
+
* 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`).
|
|
3882
|
+
* @returns {boolean}
|
|
3883
|
+
*/
|
|
3884
|
+
isPrivate() {
|
|
3885
|
+
return PRIVATE_V4.some((subnet) => this.isInSubnet(subnet));
|
|
3886
|
+
}
|
|
3887
|
+
/**
|
|
3888
|
+
* Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)).
|
|
3889
|
+
* @returns {boolean}
|
|
3890
|
+
*/
|
|
3891
|
+
isLoopback() {
|
|
3892
|
+
return this.isInSubnet(LOOPBACK_V4);
|
|
3893
|
+
}
|
|
3894
|
+
/**
|
|
3895
|
+
* 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)).
|
|
3896
|
+
* @returns {boolean}
|
|
3897
|
+
*/
|
|
3898
|
+
isLinkLocal() {
|
|
3899
|
+
return this.isInSubnet(LINK_LOCAL_V4);
|
|
3900
|
+
}
|
|
3901
|
+
/**
|
|
3902
|
+
* Returns true if the address is the unspecified address `0.0.0.0`.
|
|
3903
|
+
* @returns {boolean}
|
|
3904
|
+
*/
|
|
3905
|
+
isUnspecified() {
|
|
3906
|
+
return this.isInSubnet(UNSPECIFIED_V4);
|
|
3907
|
+
}
|
|
3908
|
+
/**
|
|
3909
|
+
* Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)).
|
|
3910
|
+
* @returns {boolean}
|
|
3911
|
+
*/
|
|
3912
|
+
isBroadcast() {
|
|
3913
|
+
return this.isInSubnet(BROADCAST_V4);
|
|
3914
|
+
}
|
|
3915
|
+
/**
|
|
3916
|
+
* 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)).
|
|
3917
|
+
* @returns {boolean}
|
|
3918
|
+
*/
|
|
3919
|
+
isCGNAT() {
|
|
3920
|
+
return this.isInSubnet(CGNAT_V4);
|
|
3787
3921
|
}
|
|
3788
3922
|
/**
|
|
3789
3923
|
* Returns a zero-padded base-2 string representation of the address
|
|
3790
|
-
* @memberof Address4
|
|
3791
|
-
* @instance
|
|
3792
3924
|
* @returns {string}
|
|
3793
3925
|
*/
|
|
3794
3926
|
binaryZeroPad() {
|
|
3795
|
-
|
|
3927
|
+
if (this._binaryZeroPad === undefined) {
|
|
3928
|
+
this._binaryZeroPad = this.bigInt().toString(2).padStart(constants.BITS, '0');
|
|
3929
|
+
}
|
|
3930
|
+
return this._binaryZeroPad;
|
|
3796
3931
|
}
|
|
3797
3932
|
/**
|
|
3798
3933
|
* Groups an IPv4 address for inclusion at the end of an IPv6 address
|
|
@@ -3808,6 +3943,17 @@ function requireIpv4 () {
|
|
|
3808
3943
|
}
|
|
3809
3944
|
}
|
|
3810
3945
|
ipv4.Address4 = Address4;
|
|
3946
|
+
const MULTICAST_V4 = new Address4('224.0.0.0/4');
|
|
3947
|
+
const PRIVATE_V4 = [
|
|
3948
|
+
new Address4('10.0.0.0/8'),
|
|
3949
|
+
new Address4('172.16.0.0/12'),
|
|
3950
|
+
new Address4('192.168.0.0/16'),
|
|
3951
|
+
];
|
|
3952
|
+
const LOOPBACK_V4 = new Address4('127.0.0.0/8');
|
|
3953
|
+
const LINK_LOCAL_V4 = new Address4('169.254.0.0/16');
|
|
3954
|
+
const UNSPECIFIED_V4 = new Address4('0.0.0.0/32');
|
|
3955
|
+
const BROADCAST_V4 = new Address4('255.255.255.255/32');
|
|
3956
|
+
const CGNAT_V4 = new Address4('100.64.0.0/10');
|
|
3811
3957
|
|
|
3812
3958
|
return ipv4;
|
|
3813
3959
|
}
|
|
@@ -3868,6 +4014,11 @@ function requireConstants () {
|
|
|
3868
4014
|
'::1/128': 'Loopback',
|
|
3869
4015
|
'ff00::/8': 'Multicast',
|
|
3870
4016
|
'fe80::/10': 'Link-local unicast',
|
|
4017
|
+
'fc00::/7': 'Unique local',
|
|
4018
|
+
'2002::/16': '6to4',
|
|
4019
|
+
'2001:db8::/32': 'Documentation',
|
|
4020
|
+
'64:ff9b::/96': 'NAT64 (well-known)',
|
|
4021
|
+
'64:ff9b:1::/48': 'NAT64 (local-use)',
|
|
3871
4022
|
};
|
|
3872
4023
|
/**
|
|
3873
4024
|
* A regular expression that matches bad characters in an IPv6 address
|
|
@@ -3907,15 +4058,24 @@ function requireHelpers$1 () {
|
|
|
3907
4058
|
if (hasRequiredHelpers$1) return helpers;
|
|
3908
4059
|
hasRequiredHelpers$1 = 1;
|
|
3909
4060
|
Object.defineProperty(helpers, "__esModule", { value: true });
|
|
4061
|
+
helpers.escapeHtml = escapeHtml;
|
|
3910
4062
|
helpers.spanAllZeroes = spanAllZeroes;
|
|
3911
4063
|
helpers.spanAll = spanAll;
|
|
3912
4064
|
helpers.spanLeadingZeroes = spanLeadingZeroes;
|
|
3913
4065
|
helpers.simpleGroup = simpleGroup;
|
|
4066
|
+
function escapeHtml(s) {
|
|
4067
|
+
return s
|
|
4068
|
+
.replace(/&/g, '&')
|
|
4069
|
+
.replace(/</g, '<')
|
|
4070
|
+
.replace(/>/g, '>')
|
|
4071
|
+
.replace(/"/g, '"')
|
|
4072
|
+
.replace(/'/g, ''');
|
|
4073
|
+
}
|
|
3914
4074
|
/**
|
|
3915
4075
|
* @returns {String} the string with all zeroes contained in a <span>
|
|
3916
4076
|
*/
|
|
3917
4077
|
function spanAllZeroes(s) {
|
|
3918
|
-
return s.replace(/(0+)/g, '<span class="zero">$1</span>');
|
|
4078
|
+
return escapeHtml(s).replace(/(0+)/g, '<span class="zero">$1</span>');
|
|
3919
4079
|
}
|
|
3920
4080
|
/**
|
|
3921
4081
|
* @returns {String} the string with each character contained in a <span>
|
|
@@ -3923,11 +4083,11 @@ function requireHelpers$1 () {
|
|
|
3923
4083
|
function spanAll(s, offset = 0) {
|
|
3924
4084
|
const letters = s.split('');
|
|
3925
4085
|
return letters
|
|
3926
|
-
.map((n, i) => `<span class="digit value-${n} position-${i + offset}">${spanAllZeroes(n)}</span>`)
|
|
4086
|
+
.map((n, i) => `<span class="digit value-${escapeHtml(n)} position-${i + offset}">${spanAllZeroes(n)}</span>`)
|
|
3927
4087
|
.join('');
|
|
3928
4088
|
}
|
|
3929
4089
|
function spanLeadingZeroesSimple(group) {
|
|
3930
|
-
return group.replace(/^(0+)/, '<span class="zero">$1</span>');
|
|
4090
|
+
return escapeHtml(group).replace(/^(0+)/, '<span class="zero">$1</span>');
|
|
3931
4091
|
}
|
|
3932
4092
|
/**
|
|
3933
4093
|
* @returns {String} the string with leading zeroes contained in a <span>
|
|
@@ -3989,7 +4149,7 @@ function requireRegularExpressions () {
|
|
|
3989
4149
|
regularExpressions.padGroup = padGroup;
|
|
3990
4150
|
regularExpressions.simpleRegularExpression = simpleRegularExpression;
|
|
3991
4151
|
regularExpressions.possibleElisions = possibleElisions;
|
|
3992
|
-
const v6 = __importStar(requireConstants());
|
|
4152
|
+
const v6 = __importStar(/*@__PURE__*/ requireConstants());
|
|
3993
4153
|
function groupPossibilities(possibilities) {
|
|
3994
4154
|
return `(${possibilities.join('|')})`;
|
|
3995
4155
|
}
|
|
@@ -4089,14 +4249,15 @@ function requireIpv6 () {
|
|
|
4089
4249
|
};
|
|
4090
4250
|
Object.defineProperty(ipv6, "__esModule", { value: true });
|
|
4091
4251
|
ipv6.Address6 = void 0;
|
|
4092
|
-
const common = __importStar(requireCommon());
|
|
4093
|
-
const constants4 = __importStar(requireConstants$1());
|
|
4094
|
-
const constants6 = __importStar(requireConstants());
|
|
4095
|
-
const helpers = __importStar(requireHelpers$1());
|
|
4096
|
-
const ipv4_1 = requireIpv4();
|
|
4097
|
-
const regular_expressions_1 = requireRegularExpressions();
|
|
4098
|
-
const address_error_1 = requireAddressError();
|
|
4099
|
-
const common_1 = requireCommon();
|
|
4252
|
+
const common = __importStar(/*@__PURE__*/ requireCommon());
|
|
4253
|
+
const constants4 = __importStar(/*@__PURE__*/ requireConstants$1());
|
|
4254
|
+
const constants6 = __importStar(/*@__PURE__*/ requireConstants());
|
|
4255
|
+
const helpers = __importStar(/*@__PURE__*/ requireHelpers$1());
|
|
4256
|
+
const ipv4_1 = /*@__PURE__*/ requireIpv4();
|
|
4257
|
+
const regular_expressions_1 = /*@__PURE__*/ requireRegularExpressions();
|
|
4258
|
+
const address_error_1 = /*@__PURE__*/ requireAddressError();
|
|
4259
|
+
const common_1 = /*@__PURE__*/ requireCommon();
|
|
4260
|
+
const isCorrect6 = common.isCorrect(constants6.BITS);
|
|
4100
4261
|
function assert(condition) {
|
|
4101
4262
|
if (!condition) {
|
|
4102
4263
|
throw new Error('Assertion failed.');
|
|
@@ -4140,7 +4301,6 @@ function requireIpv6 () {
|
|
|
4140
4301
|
}
|
|
4141
4302
|
/**
|
|
4142
4303
|
* Represents an IPv6 address
|
|
4143
|
-
* @class Address6
|
|
4144
4304
|
* @param {string} address - An IPv6 address string
|
|
4145
4305
|
* @param {number} [groups=8] - How many octets to parse
|
|
4146
4306
|
* @example
|
|
@@ -4157,18 +4317,14 @@ function requireIpv6 () {
|
|
|
4157
4317
|
// #region Attributes
|
|
4158
4318
|
/**
|
|
4159
4319
|
* Returns true if the given address is in the subnet of the current address
|
|
4160
|
-
* @memberof Address6
|
|
4161
|
-
* @instance
|
|
4162
4320
|
* @returns {boolean}
|
|
4163
4321
|
*/
|
|
4164
4322
|
this.isInSubnet = common.isInSubnet;
|
|
4165
4323
|
/**
|
|
4166
4324
|
* Returns true if the address is correct, false otherwise
|
|
4167
|
-
* @memberof Address6
|
|
4168
|
-
* @instance
|
|
4169
4325
|
* @returns {boolean}
|
|
4170
4326
|
*/
|
|
4171
|
-
this.isCorrect =
|
|
4327
|
+
this.isCorrect = isCorrect6;
|
|
4172
4328
|
if (optionalGroups === undefined) {
|
|
4173
4329
|
this.groups = constants6.GROUPS;
|
|
4174
4330
|
}
|
|
@@ -4199,6 +4355,13 @@ function requireIpv6 () {
|
|
|
4199
4355
|
this.addressMinusSuffix = address;
|
|
4200
4356
|
this.parsedAddress = this.parse(this.addressMinusSuffix);
|
|
4201
4357
|
}
|
|
4358
|
+
/**
|
|
4359
|
+
* Returns true if the given string is a valid IPv6 address (with optional
|
|
4360
|
+
* CIDR subnet and zone identifier), false otherwise. Host bits in the
|
|
4361
|
+
* subnet portion are allowed (e.g. `2001:db8::1/32` is valid); for strict
|
|
4362
|
+
* network-address validation compare `correctForm()` to
|
|
4363
|
+
* `startAddress().correctForm()`, or use `networkForm()`.
|
|
4364
|
+
*/
|
|
4202
4365
|
static isValid(address) {
|
|
4203
4366
|
try {
|
|
4204
4367
|
// eslint-disable-next-line no-new
|
|
@@ -4210,9 +4373,8 @@ function requireIpv6 () {
|
|
|
4210
4373
|
}
|
|
4211
4374
|
}
|
|
4212
4375
|
/**
|
|
4213
|
-
* Convert a BigInt to a v6 address object
|
|
4214
|
-
*
|
|
4215
|
-
* @static
|
|
4376
|
+
* Convert a BigInt to a v6 address object. The value must be in the
|
|
4377
|
+
* range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown.
|
|
4216
4378
|
* @param {bigint} bigInt - a BigInt to convert
|
|
4217
4379
|
* @returns {Address6}
|
|
4218
4380
|
* @example
|
|
@@ -4221,19 +4383,21 @@ function requireIpv6 () {
|
|
|
4221
4383
|
* address.correctForm(); // '::e8:d4a5:1000'
|
|
4222
4384
|
*/
|
|
4223
4385
|
static fromBigInt(bigInt) {
|
|
4386
|
+
if (bigInt < 0n || bigInt > (1n << BigInt(constants6.BITS)) - 1n) {
|
|
4387
|
+
throw new address_error_1.AddressError('IPv6 BigInt must be in the range 0 to 2**128 - 1');
|
|
4388
|
+
}
|
|
4224
4389
|
const hex = bigInt.toString(16).padStart(32, '0');
|
|
4225
4390
|
const groups = [];
|
|
4226
|
-
let i;
|
|
4227
|
-
for (i = 0; i < constants6.GROUPS; i++) {
|
|
4391
|
+
for (let i = 0; i < constants6.GROUPS; i++) {
|
|
4228
4392
|
groups.push(hex.slice(i * 4, (i + 1) * 4));
|
|
4229
4393
|
}
|
|
4230
4394
|
return new Address6(groups.join(':'));
|
|
4231
4395
|
}
|
|
4232
4396
|
/**
|
|
4233
|
-
*
|
|
4234
|
-
*
|
|
4235
|
-
*
|
|
4236
|
-
*
|
|
4397
|
+
* Parse a URL (with optional bracketed host and port) into an address and
|
|
4398
|
+
* port. Returns either `{ address, port }` on success or
|
|
4399
|
+
* `{ error, address: null, port: null }` if the URL could not be parsed.
|
|
4400
|
+
* Ports are returned as numbers (or `null` if absent or out of range).
|
|
4237
4401
|
* @example
|
|
4238
4402
|
* var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/');
|
|
4239
4403
|
* addressAndPort.address.correctForm(); // 'ffff::'
|
|
@@ -4292,10 +4456,92 @@ function requireIpv6 () {
|
|
|
4292
4456
|
port,
|
|
4293
4457
|
};
|
|
4294
4458
|
}
|
|
4459
|
+
/**
|
|
4460
|
+
* Construct an `Address6` from an address and a hex subnet mask given as
|
|
4461
|
+
* separate strings (e.g. as returned by Node's `os.networkInterfaces()`).
|
|
4462
|
+
* Throws `AddressError` if the mask is non-contiguous (e.g.
|
|
4463
|
+
* `ffff::ffff`).
|
|
4464
|
+
* @example
|
|
4465
|
+
* var address = Address6.fromAddressAndMask('fe80::1', 'ffff:ffff:ffff:ffff::');
|
|
4466
|
+
* address.subnetMask; // 64
|
|
4467
|
+
*/
|
|
4468
|
+
static fromAddressAndMask(address, mask) {
|
|
4469
|
+
const bits = common.prefixLengthFromMask(new Address6(mask).bigInt(), constants6.BITS);
|
|
4470
|
+
return new Address6(`${address}/${bits}`);
|
|
4471
|
+
}
|
|
4472
|
+
/**
|
|
4473
|
+
* Construct an `Address6` from an address and a Cisco-style wildcard mask
|
|
4474
|
+
* given as separate strings (e.g. `::ffff:ffff:ffff:ffff` for a `/64`).
|
|
4475
|
+
* The wildcard mask is the bitwise inverse of the subnet mask. Throws
|
|
4476
|
+
* `AddressError` if the mask is non-contiguous.
|
|
4477
|
+
* @example
|
|
4478
|
+
* var address = Address6.fromAddressAndWildcardMask('fe80::1', '::ffff:ffff:ffff:ffff');
|
|
4479
|
+
* address.subnetMask; // 64
|
|
4480
|
+
*/
|
|
4481
|
+
static fromAddressAndWildcardMask(address, wildcardMask) {
|
|
4482
|
+
const wildcard = new Address6(wildcardMask).bigInt();
|
|
4483
|
+
const allOnes = (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1);
|
|
4484
|
+
// eslint-disable-next-line no-bitwise
|
|
4485
|
+
const mask = wildcard ^ allOnes;
|
|
4486
|
+
const bits = common.prefixLengthFromMask(mask, constants6.BITS);
|
|
4487
|
+
return new Address6(`${address}/${bits}`);
|
|
4488
|
+
}
|
|
4489
|
+
/**
|
|
4490
|
+
* Construct an `Address6` from a wildcard pattern with trailing `*`
|
|
4491
|
+
* groups. The number of trailing wildcards determines the prefix
|
|
4492
|
+
* length: each `*` represents 16 bits. `::` is expanded to zero groups
|
|
4493
|
+
* (not wildcards) before evaluating trailing wildcards.
|
|
4494
|
+
*
|
|
4495
|
+
* Only trailing whole-group wildcards are supported. Partial-group
|
|
4496
|
+
* wildcards (e.g. `2001:db8::0*`) and interior wildcards (e.g.
|
|
4497
|
+
* `*::1`) throw `AddressError`.
|
|
4498
|
+
* @example
|
|
4499
|
+
* Address6.fromWildcard('2001:db8:*:*:*:*:*:*').subnet; // '/32'
|
|
4500
|
+
* Address6.fromWildcard('2001:db8::*').subnet; // '/112'
|
|
4501
|
+
* Address6.fromWildcard('*:*:*:*:*:*:*:*').subnet; // '/0'
|
|
4502
|
+
*/
|
|
4503
|
+
static fromWildcard(input) {
|
|
4504
|
+
if (input.includes('%') || input.includes('/')) {
|
|
4505
|
+
throw new address_error_1.AddressError('Wildcard pattern must not include a zone or CIDR suffix');
|
|
4506
|
+
}
|
|
4507
|
+
const halves = input.split('::');
|
|
4508
|
+
if (halves.length > 2) {
|
|
4509
|
+
throw new address_error_1.AddressError("Wildcard pattern cannot contain more than one '::'");
|
|
4510
|
+
}
|
|
4511
|
+
let groups;
|
|
4512
|
+
if (halves.length === 2) {
|
|
4513
|
+
const left = halves[0] === '' ? [] : halves[0].split(':');
|
|
4514
|
+
const right = halves[1] === '' ? [] : halves[1].split(':');
|
|
4515
|
+
const remaining = constants6.GROUPS - left.length - right.length;
|
|
4516
|
+
if (remaining < 1) {
|
|
4517
|
+
throw new address_error_1.AddressError("Wildcard pattern with '::' has too many groups");
|
|
4518
|
+
}
|
|
4519
|
+
groups = [...left, ...new Array(remaining).fill('0'), ...right];
|
|
4520
|
+
}
|
|
4521
|
+
else {
|
|
4522
|
+
groups = input.split(':');
|
|
4523
|
+
}
|
|
4524
|
+
if (groups.length !== constants6.GROUPS) {
|
|
4525
|
+
throw new address_error_1.AddressError('Wildcard pattern must have 8 groups');
|
|
4526
|
+
}
|
|
4527
|
+
let firstWildcard = -1;
|
|
4528
|
+
for (let i = 0; i < groups.length; i++) {
|
|
4529
|
+
if (groups[i] === '*') {
|
|
4530
|
+
if (firstWildcard === -1) {
|
|
4531
|
+
firstWildcard = i;
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4534
|
+
else if (firstWildcard !== -1) {
|
|
4535
|
+
throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing groups (e.g. `2001:db8:*:*:*:*:*:*`)');
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
|
|
4539
|
+
const replaced = groups.map((g) => (g === '*' ? '0' : g));
|
|
4540
|
+
const subnetBits = constants6.BITS - trailing * 16;
|
|
4541
|
+
return new Address6(`${replaced.join(':')}/${subnetBits}`);
|
|
4542
|
+
}
|
|
4295
4543
|
/**
|
|
4296
4544
|
* Create an IPv6-mapped address given an IPv4 address
|
|
4297
|
-
* @memberof Address6
|
|
4298
|
-
* @static
|
|
4299
4545
|
* @param {string} address - An IPv4 address string
|
|
4300
4546
|
* @returns {Address6}
|
|
4301
4547
|
* @example
|
|
@@ -4310,8 +4556,6 @@ function requireIpv6 () {
|
|
|
4310
4556
|
}
|
|
4311
4557
|
/**
|
|
4312
4558
|
* Return an address from ip6.arpa form
|
|
4313
|
-
* @memberof Address6
|
|
4314
|
-
* @static
|
|
4315
4559
|
* @param {string} arpaFormAddress - an 'ip6.arpa' form address
|
|
4316
4560
|
* @returns {Adress6}
|
|
4317
4561
|
* @example
|
|
@@ -4336,8 +4580,6 @@ function requireIpv6 () {
|
|
|
4336
4580
|
}
|
|
4337
4581
|
/**
|
|
4338
4582
|
* Return the Microsoft UNC transcription of the address
|
|
4339
|
-
* @memberof Address6
|
|
4340
|
-
* @instance
|
|
4341
4583
|
* @returns {String} the Microsoft UNC transcription of the address
|
|
4342
4584
|
*/
|
|
4343
4585
|
microsoftTranscription() {
|
|
@@ -4345,8 +4587,6 @@ function requireIpv6 () {
|
|
|
4345
4587
|
}
|
|
4346
4588
|
/**
|
|
4347
4589
|
* Return the first n bits of the address, defaulting to the subnet mask
|
|
4348
|
-
* @memberof Address6
|
|
4349
|
-
* @instance
|
|
4350
4590
|
* @param {number} [mask=subnet] - the number of bits to mask
|
|
4351
4591
|
* @returns {String} the first n bits of the address as a string
|
|
4352
4592
|
*/
|
|
@@ -4355,8 +4595,6 @@ function requireIpv6 () {
|
|
|
4355
4595
|
}
|
|
4356
4596
|
/**
|
|
4357
4597
|
* Return the number of possible subnets of a given size in the address
|
|
4358
|
-
* @memberof Address6
|
|
4359
|
-
* @instance
|
|
4360
4598
|
* @param {number} [subnetSize=128] - the subnet size
|
|
4361
4599
|
* @returns {String}
|
|
4362
4600
|
*/
|
|
@@ -4372,8 +4610,6 @@ function requireIpv6 () {
|
|
|
4372
4610
|
}
|
|
4373
4611
|
/**
|
|
4374
4612
|
* Helper function getting start address.
|
|
4375
|
-
* @memberof Address6
|
|
4376
|
-
* @instance
|
|
4377
4613
|
* @returns {bigint}
|
|
4378
4614
|
*/
|
|
4379
4615
|
_startAddress() {
|
|
@@ -4382,8 +4618,6 @@ function requireIpv6 () {
|
|
|
4382
4618
|
/**
|
|
4383
4619
|
* The first address in the range given by this address' subnet
|
|
4384
4620
|
* Often referred to as the Network Address.
|
|
4385
|
-
* @memberof Address6
|
|
4386
|
-
* @instance
|
|
4387
4621
|
* @returns {Address6}
|
|
4388
4622
|
*/
|
|
4389
4623
|
startAddress() {
|
|
@@ -4392,8 +4626,6 @@ function requireIpv6 () {
|
|
|
4392
4626
|
/**
|
|
4393
4627
|
* The first host address in the range given by this address's subnet ie
|
|
4394
4628
|
* the first address after the Network Address
|
|
4395
|
-
* @memberof Address6
|
|
4396
|
-
* @instance
|
|
4397
4629
|
* @returns {Address6}
|
|
4398
4630
|
*/
|
|
4399
4631
|
startAddressExclusive() {
|
|
@@ -4402,8 +4634,6 @@ function requireIpv6 () {
|
|
|
4402
4634
|
}
|
|
4403
4635
|
/**
|
|
4404
4636
|
* Helper function getting end address.
|
|
4405
|
-
* @memberof Address6
|
|
4406
|
-
* @instance
|
|
4407
4637
|
* @returns {bigint}
|
|
4408
4638
|
*/
|
|
4409
4639
|
_endAddress() {
|
|
@@ -4412,8 +4642,6 @@ function requireIpv6 () {
|
|
|
4412
4642
|
/**
|
|
4413
4643
|
* The last address in the range given by this address' subnet
|
|
4414
4644
|
* Often referred to as the Broadcast
|
|
4415
|
-
* @memberof Address6
|
|
4416
|
-
* @instance
|
|
4417
4645
|
* @returns {Address6}
|
|
4418
4646
|
*/
|
|
4419
4647
|
endAddress() {
|
|
@@ -4422,8 +4650,6 @@ function requireIpv6 () {
|
|
|
4422
4650
|
/**
|
|
4423
4651
|
* The last host address in the range given by this address's subnet ie
|
|
4424
4652
|
* the last address prior to the Broadcast Address
|
|
4425
|
-
* @memberof Address6
|
|
4426
|
-
* @instance
|
|
4427
4653
|
* @returns {Address6}
|
|
4428
4654
|
*/
|
|
4429
4655
|
endAddressExclusive() {
|
|
@@ -4431,36 +4657,73 @@ function requireIpv6 () {
|
|
|
4431
4657
|
return Address6.fromBigInt(this._endAddress() - adjust);
|
|
4432
4658
|
}
|
|
4433
4659
|
/**
|
|
4434
|
-
*
|
|
4435
|
-
*
|
|
4436
|
-
* @
|
|
4660
|
+
* The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a
|
|
4661
|
+
* `/64`. Returns an `Address6`; call `.correctForm()` for the string.
|
|
4662
|
+
* @returns {Address6}
|
|
4663
|
+
*/
|
|
4664
|
+
subnetMaskAddress() {
|
|
4665
|
+
return Address6.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants6.BITS - this.subnetMask)}`));
|
|
4666
|
+
}
|
|
4667
|
+
/**
|
|
4668
|
+
* The Cisco-style wildcard mask, e.g. `::ffff:ffff:ffff:ffff` for a
|
|
4669
|
+
* `/64`. This is the bitwise inverse of `subnetMaskAddress()`. Returns
|
|
4670
|
+
* an `Address6`; call `.correctForm()` for the string.
|
|
4671
|
+
* @returns {Address6}
|
|
4672
|
+
*/
|
|
4673
|
+
wildcardMask() {
|
|
4674
|
+
return Address6.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants6.BITS - this.subnetMask)}`));
|
|
4675
|
+
}
|
|
4676
|
+
/**
|
|
4677
|
+
* The network address in CIDR string form, e.g. `2001:db8::/32` for
|
|
4678
|
+
* `2001:db8::1/32`. For an address with no explicit subnet the prefix
|
|
4679
|
+
* is `/128`, e.g. `networkForm()` on `2001:db8::1` returns
|
|
4680
|
+
* `2001:db8::1/128`.
|
|
4681
|
+
* @returns {string}
|
|
4682
|
+
*/
|
|
4683
|
+
networkForm() {
|
|
4684
|
+
return `${this.startAddress().correctForm()}/${this.subnetMask}`;
|
|
4685
|
+
}
|
|
4686
|
+
/**
|
|
4687
|
+
* Return the scope of the address. The 4-bit scope field
|
|
4688
|
+
* ([RFC 4291 §2.7](https://datatracker.ietf.org/doc/html/rfc4291#section-2.7))
|
|
4689
|
+
* is only defined for multicast addresses; for unicast addresses the scope
|
|
4690
|
+
* is derived from the address type per
|
|
4691
|
+
* [RFC 4007 §6](https://datatracker.ietf.org/doc/html/rfc4007#section-6).
|
|
4437
4692
|
* @returns {String}
|
|
4438
4693
|
*/
|
|
4439
4694
|
getScope() {
|
|
4440
|
-
|
|
4441
|
-
if (
|
|
4442
|
-
scope =
|
|
4695
|
+
const type = this.getType();
|
|
4696
|
+
if (type === 'Multicast' || type.startsWith('Multicast ')) {
|
|
4697
|
+
const scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
|
|
4698
|
+
return scope || 'Unknown';
|
|
4443
4699
|
}
|
|
4444
|
-
|
|
4700
|
+
// RFC 4291 §2.5.3: the loopback address is treated as having Link-Local
|
|
4701
|
+
// scope. (Multicast scope 1, "Interface-Local", is a different concept
|
|
4702
|
+
// used only for loopback transmission of multicast.)
|
|
4703
|
+
if (type === 'Link-local unicast' || type === 'Loopback') {
|
|
4704
|
+
return 'Link local';
|
|
4705
|
+
}
|
|
4706
|
+
// RFC 4007 §6: the unspecified address has no scope.
|
|
4707
|
+
if (type === 'Unspecified') {
|
|
4708
|
+
return 'Unknown';
|
|
4709
|
+
}
|
|
4710
|
+
return 'Global';
|
|
4445
4711
|
}
|
|
4446
4712
|
/**
|
|
4447
4713
|
* Return the type of the address
|
|
4448
|
-
* @memberof Address6
|
|
4449
|
-
* @instance
|
|
4450
4714
|
* @returns {String}
|
|
4451
4715
|
*/
|
|
4452
4716
|
getType() {
|
|
4453
|
-
for (
|
|
4454
|
-
|
|
4455
|
-
|
|
4717
|
+
for (let i = 0; i < TYPE_SUBNETS.length; i++) {
|
|
4718
|
+
const entry = TYPE_SUBNETS[i];
|
|
4719
|
+
if (this.isInSubnet(entry[0])) {
|
|
4720
|
+
return entry[1];
|
|
4456
4721
|
}
|
|
4457
4722
|
}
|
|
4458
4723
|
return 'Global unicast';
|
|
4459
4724
|
}
|
|
4460
4725
|
/**
|
|
4461
4726
|
* Return the bits in the given range as a BigInt
|
|
4462
|
-
* @memberof Address6
|
|
4463
|
-
* @instance
|
|
4464
4727
|
* @returns {bigint}
|
|
4465
4728
|
*/
|
|
4466
4729
|
getBits(start, end) {
|
|
@@ -4468,8 +4731,6 @@ function requireIpv6 () {
|
|
|
4468
4731
|
}
|
|
4469
4732
|
/**
|
|
4470
4733
|
* Return the bits in the given range as a base-2 string
|
|
4471
|
-
* @memberof Address6
|
|
4472
|
-
* @instance
|
|
4473
4734
|
* @returns {String}
|
|
4474
4735
|
*/
|
|
4475
4736
|
getBitsBase2(start, end) {
|
|
@@ -4477,8 +4738,6 @@ function requireIpv6 () {
|
|
|
4477
4738
|
}
|
|
4478
4739
|
/**
|
|
4479
4740
|
* Return the bits in the given range as a base-16 string
|
|
4480
|
-
* @memberof Address6
|
|
4481
|
-
* @instance
|
|
4482
4741
|
* @returns {String}
|
|
4483
4742
|
*/
|
|
4484
4743
|
getBitsBase16(start, end) {
|
|
@@ -4492,8 +4751,6 @@ function requireIpv6 () {
|
|
|
4492
4751
|
}
|
|
4493
4752
|
/**
|
|
4494
4753
|
* Return the bits that are set past the subnet mask length
|
|
4495
|
-
* @memberof Address6
|
|
4496
|
-
* @instance
|
|
4497
4754
|
* @returns {String}
|
|
4498
4755
|
*/
|
|
4499
4756
|
getBitsPastSubnet() {
|
|
@@ -4501,10 +4758,8 @@ function requireIpv6 () {
|
|
|
4501
4758
|
}
|
|
4502
4759
|
/**
|
|
4503
4760
|
* Return the reversed ip6.arpa form of the address
|
|
4504
|
-
* @memberof Address6
|
|
4505
4761
|
* @param {Object} options
|
|
4506
4762
|
* @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
|
|
4507
|
-
* @instance
|
|
4508
4763
|
* @returns {String}
|
|
4509
4764
|
*/
|
|
4510
4765
|
reverseForm(options) {
|
|
@@ -4530,10 +4785,10 @@ function requireIpv6 () {
|
|
|
4530
4785
|
return 'ip6.arpa.';
|
|
4531
4786
|
}
|
|
4532
4787
|
/**
|
|
4533
|
-
*
|
|
4534
|
-
*
|
|
4535
|
-
*
|
|
4536
|
-
*
|
|
4788
|
+
* Returns the address in correct form, per
|
|
4789
|
+
* [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros
|
|
4790
|
+
* stripped, the longest run of zero groups collapsed to `::`, and hex digits
|
|
4791
|
+
* lowercased (e.g. `2001:db8::1`). This is the recommended form for display.
|
|
4537
4792
|
*/
|
|
4538
4793
|
correctForm() {
|
|
4539
4794
|
let i;
|
|
@@ -4577,8 +4832,6 @@ function requireIpv6 () {
|
|
|
4577
4832
|
}
|
|
4578
4833
|
/**
|
|
4579
4834
|
* Return a zero-padded base-2 string representation of the address
|
|
4580
|
-
* @memberof Address6
|
|
4581
|
-
* @instance
|
|
4582
4835
|
* @returns {String}
|
|
4583
4836
|
* @example
|
|
4584
4837
|
* var address = new Address6('2001:4860:4001:803::1011');
|
|
@@ -4587,10 +4840,22 @@ function requireIpv6 () {
|
|
|
4587
4840
|
* // 0000000000000000000000000000000000000000000000000001000000010001'
|
|
4588
4841
|
*/
|
|
4589
4842
|
binaryZeroPad() {
|
|
4590
|
-
|
|
4843
|
+
if (this._binaryZeroPad === undefined) {
|
|
4844
|
+
this._binaryZeroPad = this.bigInt().toString(2).padStart(constants6.BITS, '0');
|
|
4845
|
+
}
|
|
4846
|
+
return this._binaryZeroPad;
|
|
4591
4847
|
}
|
|
4848
|
+
/**
|
|
4849
|
+
* Parses a v4-in-v6 string (e.g. `::ffff:192.168.0.1`) by extracting the
|
|
4850
|
+
* trailing IPv4 address into `this.address4` / `this.parsedAddress4` and
|
|
4851
|
+
* returning the address with the v4 portion converted to two v6 groups.
|
|
4852
|
+
* Used internally by `parse()`.
|
|
4853
|
+
*/
|
|
4592
4854
|
// TODO: Improve the semantics of this helper function
|
|
4593
4855
|
parse4in6(address) {
|
|
4856
|
+
if (address.indexOf('.') === -1) {
|
|
4857
|
+
return address;
|
|
4858
|
+
}
|
|
4594
4859
|
const groups = address.split(':');
|
|
4595
4860
|
const lastGroup = groups.slice(-1)[0];
|
|
4596
4861
|
const address4 = lastGroup.match(constants4.RE_ADDRESS);
|
|
@@ -4599,7 +4864,12 @@ function requireIpv6 () {
|
|
|
4599
4864
|
this.address4 = new ipv4_1.Address4(this.parsedAddress4);
|
|
4600
4865
|
for (let i = 0; i < this.address4.groups; i++) {
|
|
4601
4866
|
if (/^0[0-9]+/.test(this.address4.parsedAddress[i])) {
|
|
4602
|
-
|
|
4867
|
+
// The prefix groups haven't been through the bad-character check
|
|
4868
|
+
// yet, so escape them before including in the error HTML.
|
|
4869
|
+
const highlighted = this.address4.parsedAddress.map(spanLeadingZeroes4).join('.');
|
|
4870
|
+
const prefix = groups.slice(0, -1).map(helpers.escapeHtml).join(':');
|
|
4871
|
+
const separator = groups.length > 1 ? ':' : '';
|
|
4872
|
+
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", `${prefix}${separator}${highlighted}`);
|
|
4603
4873
|
}
|
|
4604
4874
|
}
|
|
4605
4875
|
this.v4 = true;
|
|
@@ -4608,6 +4878,13 @@ function requireIpv6 () {
|
|
|
4608
4878
|
}
|
|
4609
4879
|
return address;
|
|
4610
4880
|
}
|
|
4881
|
+
/**
|
|
4882
|
+
* Parses an IPv6 address string into its 8 hexadecimal groups (expanding
|
|
4883
|
+
* any `::` elision and any trailing v4-in-v6 portion) and stores the result
|
|
4884
|
+
* on `this.parsedAddress`. Called automatically by the constructor; you
|
|
4885
|
+
* typically don't need to call it directly. Throws `AddressError` if the
|
|
4886
|
+
* input is malformed.
|
|
4887
|
+
*/
|
|
4611
4888
|
// TODO: Make private?
|
|
4612
4889
|
parse(address) {
|
|
4613
4890
|
address = this.parse4in6(address);
|
|
@@ -4657,18 +4934,16 @@ function requireIpv6 () {
|
|
|
4657
4934
|
return groups;
|
|
4658
4935
|
}
|
|
4659
4936
|
/**
|
|
4660
|
-
*
|
|
4661
|
-
*
|
|
4662
|
-
*
|
|
4663
|
-
*
|
|
4937
|
+
* Returns the canonical (fully expanded) form of the address: all 8 groups,
|
|
4938
|
+
* each padded to 4 hex digits, with no `::` collapsing
|
|
4939
|
+
* (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and
|
|
4940
|
+
* byte-exact comparison.
|
|
4664
4941
|
*/
|
|
4665
4942
|
canonicalForm() {
|
|
4666
4943
|
return this.parsedAddress.map(paddedHex).join(':');
|
|
4667
4944
|
}
|
|
4668
4945
|
/**
|
|
4669
4946
|
* Return the decimal form of the address
|
|
4670
|
-
* @memberof Address6
|
|
4671
|
-
* @instance
|
|
4672
4947
|
* @returns {String}
|
|
4673
4948
|
*/
|
|
4674
4949
|
decimal() {
|
|
@@ -4676,8 +4951,6 @@ function requireIpv6 () {
|
|
|
4676
4951
|
}
|
|
4677
4952
|
/**
|
|
4678
4953
|
* Return the address as a BigInt
|
|
4679
|
-
* @memberof Address6
|
|
4680
|
-
* @instance
|
|
4681
4954
|
* @returns {bigint}
|
|
4682
4955
|
*/
|
|
4683
4956
|
bigInt() {
|
|
@@ -4685,8 +4958,6 @@ function requireIpv6 () {
|
|
|
4685
4958
|
}
|
|
4686
4959
|
/**
|
|
4687
4960
|
* Return the last two groups of this address as an IPv4 address string
|
|
4688
|
-
* @memberof Address6
|
|
4689
|
-
* @instance
|
|
4690
4961
|
* @returns {Address4}
|
|
4691
4962
|
* @example
|
|
4692
4963
|
* var address = new Address6('2001:4860:4001::1825:bf11');
|
|
@@ -4694,12 +4965,10 @@ function requireIpv6 () {
|
|
|
4694
4965
|
*/
|
|
4695
4966
|
to4() {
|
|
4696
4967
|
const binary = this.binaryZeroPad().split('');
|
|
4697
|
-
return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16));
|
|
4968
|
+
return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16).padStart(8, '0'));
|
|
4698
4969
|
}
|
|
4699
4970
|
/**
|
|
4700
4971
|
* Return the v4-in-v6 form of the address
|
|
4701
|
-
* @memberof Address6
|
|
4702
|
-
* @instance
|
|
4703
4972
|
* @returns {String}
|
|
4704
4973
|
*/
|
|
4705
4974
|
to4in6() {
|
|
@@ -4713,10 +4982,10 @@ function requireIpv6 () {
|
|
|
4713
4982
|
return correct + infix + address4.address;
|
|
4714
4983
|
}
|
|
4715
4984
|
/**
|
|
4716
|
-
*
|
|
4717
|
-
*
|
|
4718
|
-
*
|
|
4719
|
-
*
|
|
4985
|
+
* Decodes the Teredo tunneling fields embedded in this address. Returns the
|
|
4986
|
+
* Teredo prefix, server IPv4, client IPv4, raw flag bits, cone-NAT flag,
|
|
4987
|
+
* UDP port, and Microsoft-format flag breakdown (reserved, universal/local,
|
|
4988
|
+
* group/individual, nonce). Only meaningful for addresses in `2001::/32`.
|
|
4720
4989
|
*/
|
|
4721
4990
|
inspectTeredo() {
|
|
4722
4991
|
/*
|
|
@@ -4747,7 +5016,7 @@ function requireIpv6 () {
|
|
|
4747
5016
|
const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64));
|
|
4748
5017
|
const bitsForClient4 = this.getBits(96, 128);
|
|
4749
5018
|
// eslint-disable-next-line no-bitwise
|
|
4750
|
-
const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16));
|
|
5019
|
+
const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16).padStart(8, '0'));
|
|
4751
5020
|
const flagsBase2 = this.getBitsBase2(64, 80);
|
|
4752
5021
|
const coneNat = (0, common_1.testBit)(flagsBase2, 15);
|
|
4753
5022
|
const reserved = (0, common_1.testBit)(flagsBase2, 14);
|
|
@@ -4770,10 +5039,9 @@ function requireIpv6 () {
|
|
|
4770
5039
|
};
|
|
4771
5040
|
}
|
|
4772
5041
|
/**
|
|
4773
|
-
*
|
|
4774
|
-
*
|
|
4775
|
-
*
|
|
4776
|
-
* @returns {Object}
|
|
5042
|
+
* Decodes the 6to4 tunneling fields embedded in this address. Returns the
|
|
5043
|
+
* 6to4 prefix and the embedded IPv4 gateway address. Only meaningful for
|
|
5044
|
+
* addresses in `2002::/16`.
|
|
4777
5045
|
*/
|
|
4778
5046
|
inspect6to4() {
|
|
4779
5047
|
/*
|
|
@@ -4789,8 +5057,6 @@ function requireIpv6 () {
|
|
|
4789
5057
|
}
|
|
4790
5058
|
/**
|
|
4791
5059
|
* Return a v6 6to4 address from a v6 v4inv6 address
|
|
4792
|
-
* @memberof Address6
|
|
4793
|
-
* @instance
|
|
4794
5060
|
* @returns {Address6}
|
|
4795
5061
|
*/
|
|
4796
5062
|
to6to4() {
|
|
@@ -4807,9 +5073,80 @@ function requireIpv6 () {
|
|
|
4807
5073
|
return new Address6(addr6to4);
|
|
4808
5074
|
}
|
|
4809
5075
|
/**
|
|
4810
|
-
*
|
|
4811
|
-
*
|
|
4812
|
-
*
|
|
5076
|
+
* Embed an IPv4 address into a NAT64 IPv6 address using the encoding
|
|
5077
|
+
* defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
|
|
5078
|
+
* The default prefix is the well-known prefix `64:ff9b::/96`. The prefix
|
|
5079
|
+
* length must be one of 32, 40, 48, 56, 64, or 96; for prefixes shorter
|
|
5080
|
+
* than /64 the IPv4 octets are split around the reserved bits 64–71.
|
|
5081
|
+
* @example
|
|
5082
|
+
* Address6.fromAddress4Nat64('192.0.2.33').correctForm(); // '64:ff9b::c000:221'
|
|
5083
|
+
* Address6.fromAddress4Nat64('192.0.2.33', '2001:db8::/32').correctForm(); // '2001:db8:c000:221::'
|
|
5084
|
+
*/
|
|
5085
|
+
static fromAddress4Nat64(address, prefix = '64:ff9b::/96') {
|
|
5086
|
+
const v4 = new ipv4_1.Address4(address);
|
|
5087
|
+
const prefix6 = new Address6(prefix);
|
|
5088
|
+
const pl = prefix6.subnetMask;
|
|
5089
|
+
if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
|
|
5090
|
+
throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
|
|
5091
|
+
}
|
|
5092
|
+
const prefixBits = prefix6.binaryZeroPad();
|
|
5093
|
+
const v4Bits = v4.binaryZeroPad();
|
|
5094
|
+
let bits;
|
|
5095
|
+
if (pl === 96) {
|
|
5096
|
+
bits = prefixBits.slice(0, 96) + v4Bits;
|
|
5097
|
+
}
|
|
5098
|
+
else {
|
|
5099
|
+
const beforeU = 64 - pl;
|
|
5100
|
+
bits =
|
|
5101
|
+
prefixBits.slice(0, pl) +
|
|
5102
|
+
v4Bits.slice(0, beforeU) +
|
|
5103
|
+
'00000000' +
|
|
5104
|
+
v4Bits.slice(beforeU) +
|
|
5105
|
+
'0'.repeat(128 - 72 - (32 - beforeU));
|
|
5106
|
+
}
|
|
5107
|
+
const hex = BigInt(`0b${bits}`).toString(16).padStart(32, '0');
|
|
5108
|
+
const groups = [];
|
|
5109
|
+
for (let i = 0; i < 8; i++) {
|
|
5110
|
+
groups.push(hex.slice(i * 4, (i + 1) * 4));
|
|
5111
|
+
}
|
|
5112
|
+
return new Address6(groups.join(':'));
|
|
5113
|
+
}
|
|
5114
|
+
/**
|
|
5115
|
+
* Extract the embedded IPv4 address from a NAT64 IPv6 address using the
|
|
5116
|
+
* encoding defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
|
|
5117
|
+
* The default prefix is the well-known prefix `64:ff9b::/96`. Returns
|
|
5118
|
+
* `null` if this address is not contained within the given prefix.
|
|
5119
|
+
* @example
|
|
5120
|
+
* new Address6('64:ff9b::c000:221').toAddress4Nat64()!.correctForm(); // '192.0.2.33'
|
|
5121
|
+
*/
|
|
5122
|
+
toAddress4Nat64(prefix = '64:ff9b::/96') {
|
|
5123
|
+
const prefix6 = new Address6(prefix);
|
|
5124
|
+
const pl = prefix6.subnetMask;
|
|
5125
|
+
if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
|
|
5126
|
+
throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
|
|
5127
|
+
}
|
|
5128
|
+
if (!this.isInSubnet(prefix6)) {
|
|
5129
|
+
return null;
|
|
5130
|
+
}
|
|
5131
|
+
const bits = this.binaryZeroPad();
|
|
5132
|
+
let v4Bits;
|
|
5133
|
+
if (pl === 96) {
|
|
5134
|
+
v4Bits = bits.slice(96, 128);
|
|
5135
|
+
}
|
|
5136
|
+
else {
|
|
5137
|
+
const beforeU = 64 - pl;
|
|
5138
|
+
v4Bits = bits.slice(pl, pl + beforeU) + bits.slice(72, 72 + (32 - beforeU));
|
|
5139
|
+
}
|
|
5140
|
+
const octets = [];
|
|
5141
|
+
for (let i = 0; i < 4; i++) {
|
|
5142
|
+
octets.push(parseInt(v4Bits.slice(i * 8, (i + 1) * 8), 2).toString());
|
|
5143
|
+
}
|
|
5144
|
+
return new ipv4_1.Address4(octets.join('.'));
|
|
5145
|
+
}
|
|
5146
|
+
/**
|
|
5147
|
+
* Return a byte array.
|
|
5148
|
+
*
|
|
5149
|
+
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`.
|
|
4813
5150
|
* @returns {Array}
|
|
4814
5151
|
*/
|
|
4815
5152
|
toByteArray() {
|
|
@@ -4823,27 +5160,27 @@ function requireIpv6 () {
|
|
|
4823
5160
|
return bytes;
|
|
4824
5161
|
}
|
|
4825
5162
|
/**
|
|
4826
|
-
* Return an unsigned byte array
|
|
4827
|
-
*
|
|
4828
|
-
*
|
|
5163
|
+
* Return an unsigned byte array.
|
|
5164
|
+
*
|
|
5165
|
+
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`.
|
|
4829
5166
|
* @returns {Array}
|
|
4830
5167
|
*/
|
|
4831
5168
|
toUnsignedByteArray() {
|
|
4832
5169
|
return this.toByteArray().map(unsignByte);
|
|
4833
5170
|
}
|
|
4834
5171
|
/**
|
|
4835
|
-
* Convert a byte array to an Address6 object
|
|
4836
|
-
*
|
|
4837
|
-
*
|
|
5172
|
+
* Convert a byte array to an Address6 object.
|
|
5173
|
+
*
|
|
5174
|
+
* To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`.
|
|
4838
5175
|
* @returns {Address6}
|
|
4839
5176
|
*/
|
|
4840
5177
|
static fromByteArray(bytes) {
|
|
4841
5178
|
return this.fromUnsignedByteArray(bytes.map(unsignByte));
|
|
4842
5179
|
}
|
|
4843
5180
|
/**
|
|
4844
|
-
* Convert an unsigned byte array to an Address6 object
|
|
4845
|
-
*
|
|
4846
|
-
*
|
|
5181
|
+
* Convert an unsigned byte array to an Address6 object.
|
|
5182
|
+
*
|
|
5183
|
+
* To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`.
|
|
4847
5184
|
* @returns {Address6}
|
|
4848
5185
|
*/
|
|
4849
5186
|
static fromUnsignedByteArray(bytes) {
|
|
@@ -4858,8 +5195,6 @@ function requireIpv6 () {
|
|
|
4858
5195
|
}
|
|
4859
5196
|
/**
|
|
4860
5197
|
* Returns true if the address is in the canonical form, false otherwise
|
|
4861
|
-
* @memberof Address6
|
|
4862
|
-
* @instance
|
|
4863
5198
|
* @returns {boolean}
|
|
4864
5199
|
*/
|
|
4865
5200
|
isCanonical() {
|
|
@@ -4867,8 +5202,6 @@ function requireIpv6 () {
|
|
|
4867
5202
|
}
|
|
4868
5203
|
/**
|
|
4869
5204
|
* Returns true if the address is a link local address, false otherwise
|
|
4870
|
-
* @memberof Address6
|
|
4871
|
-
* @instance
|
|
4872
5205
|
* @returns {boolean}
|
|
4873
5206
|
*/
|
|
4874
5207
|
isLinkLocal() {
|
|
@@ -4881,53 +5214,81 @@ function requireIpv6 () {
|
|
|
4881
5214
|
}
|
|
4882
5215
|
/**
|
|
4883
5216
|
* Returns true if the address is a multicast address, false otherwise
|
|
4884
|
-
* @memberof Address6
|
|
4885
|
-
* @instance
|
|
4886
5217
|
* @returns {boolean}
|
|
4887
5218
|
*/
|
|
4888
5219
|
isMulticast() {
|
|
4889
|
-
|
|
5220
|
+
const type = this.getType();
|
|
5221
|
+
return type === 'Multicast' || type.startsWith('Multicast ');
|
|
4890
5222
|
}
|
|
4891
5223
|
/**
|
|
4892
|
-
* Returns true if the address
|
|
4893
|
-
*
|
|
4894
|
-
*
|
|
5224
|
+
* Returns true if the address was written in v4-in-v6 dotted-quad notation
|
|
5225
|
+
* (e.g. `::ffff:127.0.0.1`), false otherwise. This is a notation-level flag
|
|
5226
|
+
* and does not reflect whether the address bits lie in the IPv4-mapped
|
|
5227
|
+
* (`::ffff:0:0/96`) subnet — for that, see {@link isMapped4}.
|
|
4895
5228
|
* @returns {boolean}
|
|
4896
5229
|
*/
|
|
4897
5230
|
is4() {
|
|
4898
5231
|
return this.v4;
|
|
4899
5232
|
}
|
|
5233
|
+
/**
|
|
5234
|
+
* Returns true if the address is an IPv4-mapped IPv6 address in
|
|
5235
|
+
* `::ffff:0:0/96` ([RFC 4291 §2.5.5.2](https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2)),
|
|
5236
|
+
* false otherwise. Unlike {@link is4}, this checks the underlying address
|
|
5237
|
+
* bits rather than the textual notation, so `::ffff:127.0.0.1` and
|
|
5238
|
+
* `::ffff:7f00:1` both return true.
|
|
5239
|
+
* @returns {boolean}
|
|
5240
|
+
*/
|
|
5241
|
+
isMapped4() {
|
|
5242
|
+
return this.isInSubnet(IPV4_MAPPED_SUBNET);
|
|
5243
|
+
}
|
|
4900
5244
|
/**
|
|
4901
5245
|
* Returns true if the address is a Teredo address, false otherwise
|
|
4902
|
-
* @memberof Address6
|
|
4903
|
-
* @instance
|
|
4904
5246
|
* @returns {boolean}
|
|
4905
5247
|
*/
|
|
4906
5248
|
isTeredo() {
|
|
4907
|
-
return this.isInSubnet(
|
|
5249
|
+
return this.isInSubnet(TEREDO_SUBNET);
|
|
4908
5250
|
}
|
|
4909
5251
|
/**
|
|
4910
5252
|
* Returns true if the address is a 6to4 address, false otherwise
|
|
4911
|
-
* @memberof Address6
|
|
4912
|
-
* @instance
|
|
4913
5253
|
* @returns {boolean}
|
|
4914
5254
|
*/
|
|
4915
5255
|
is6to4() {
|
|
4916
|
-
return this.isInSubnet(
|
|
5256
|
+
return this.isInSubnet(SIX_TO_FOUR_SUBNET);
|
|
4917
5257
|
}
|
|
4918
5258
|
/**
|
|
4919
5259
|
* Returns true if the address is a loopback address, false otherwise
|
|
4920
|
-
* @memberof Address6
|
|
4921
|
-
* @instance
|
|
4922
5260
|
* @returns {boolean}
|
|
4923
5261
|
*/
|
|
4924
5262
|
isLoopback() {
|
|
4925
5263
|
return this.getType() === 'Loopback';
|
|
4926
5264
|
}
|
|
5265
|
+
/**
|
|
5266
|
+
* 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.
|
|
5267
|
+
* @returns {boolean}
|
|
5268
|
+
*/
|
|
5269
|
+
isULA() {
|
|
5270
|
+
return this.isInSubnet(ULA_SUBNET);
|
|
5271
|
+
}
|
|
5272
|
+
/**
|
|
5273
|
+
* Returns true if the address is the unspecified address `::`.
|
|
5274
|
+
* @returns {boolean}
|
|
5275
|
+
*/
|
|
5276
|
+
isUnspecified() {
|
|
5277
|
+
return this.getType() === 'Unspecified';
|
|
5278
|
+
}
|
|
5279
|
+
/**
|
|
5280
|
+
* Returns true if the address is in the documentation prefix `2001:db8::/32` ([RFC 3849](https://datatracker.ietf.org/doc/html/rfc3849)).
|
|
5281
|
+
* @returns {boolean}
|
|
5282
|
+
*/
|
|
5283
|
+
isDocumentation() {
|
|
5284
|
+
return this.isInSubnet(DOCUMENTATION_SUBNET);
|
|
5285
|
+
}
|
|
4927
5286
|
// #endregion
|
|
4928
5287
|
// #region HTML
|
|
4929
5288
|
/**
|
|
4930
|
-
*
|
|
5289
|
+
* Returns the address as an HTTP URL with the host bracketed, e.g.
|
|
5290
|
+
* `http://[2001:db8::1]/`. If `optionalPort` is provided it is appended,
|
|
5291
|
+
* e.g. `http://[2001:db8::1]:8080/`.
|
|
4931
5292
|
*/
|
|
4932
5293
|
href(optionalPort) {
|
|
4933
5294
|
if (optionalPort === undefined) {
|
|
@@ -4939,7 +5300,12 @@ function requireIpv6 () {
|
|
|
4939
5300
|
return `http://[${this.correctForm()}]${optionalPort}/`;
|
|
4940
5301
|
}
|
|
4941
5302
|
/**
|
|
4942
|
-
*
|
|
5303
|
+
* Returns an HTML `<a>` element whose `href` encodes the address in a URL
|
|
5304
|
+
* hash fragment (default prefix `/#address=`). Useful for linking between
|
|
5305
|
+
* pages of an address-inspector UI.
|
|
5306
|
+
* @param options.className - CSS class for the rendered `<a>` element
|
|
5307
|
+
* @param options.prefix - hash prefix prepended to the address (default `/#address=`)
|
|
5308
|
+
* @param options.v4 - when true, render the address in v4-in-v6 form
|
|
4943
5309
|
*/
|
|
4944
5310
|
link(options) {
|
|
4945
5311
|
if (!options) {
|
|
@@ -4959,10 +5325,13 @@ function requireIpv6 () {
|
|
|
4959
5325
|
formFunction = this.to4in6;
|
|
4960
5326
|
}
|
|
4961
5327
|
const form = formFunction.call(this);
|
|
5328
|
+
const safeHref = helpers.escapeHtml(`${options.prefix}${form}`);
|
|
5329
|
+
const safeForm = helpers.escapeHtml(form);
|
|
4962
5330
|
if (options.className) {
|
|
4963
|
-
|
|
5331
|
+
const safeClass = helpers.escapeHtml(options.className);
|
|
5332
|
+
return `<a href="${safeHref}" class="${safeClass}">${safeForm}</a>`;
|
|
4964
5333
|
}
|
|
4965
|
-
return `<a href="${
|
|
5334
|
+
return `<a href="${safeHref}">${safeForm}</a>`;
|
|
4966
5335
|
}
|
|
4967
5336
|
/**
|
|
4968
5337
|
* Groups an address
|
|
@@ -4971,13 +5340,13 @@ function requireIpv6 () {
|
|
|
4971
5340
|
group() {
|
|
4972
5341
|
if (this.elidedGroups === 0) {
|
|
4973
5342
|
// The simple case
|
|
4974
|
-
return helpers.simpleGroup(this.
|
|
5343
|
+
return helpers.simpleGroup(this.addressMinusSuffix).join(':');
|
|
4975
5344
|
}
|
|
4976
5345
|
assert(typeof this.elidedGroups === 'number');
|
|
4977
5346
|
assert(typeof this.elisionBegin === 'number');
|
|
4978
5347
|
// The elided case
|
|
4979
5348
|
const output = [];
|
|
4980
|
-
const [left, right] = this.
|
|
5349
|
+
const [left, right] = this.addressMinusSuffix.split('::');
|
|
4981
5350
|
if (left.length) {
|
|
4982
5351
|
output.push(...helpers.simpleGroup(left));
|
|
4983
5352
|
}
|
|
@@ -5007,8 +5376,6 @@ function requireIpv6 () {
|
|
|
5007
5376
|
/**
|
|
5008
5377
|
* Generate a regular expression string that can be used to find or validate
|
|
5009
5378
|
* all variations of this address
|
|
5010
|
-
* @memberof Address6
|
|
5011
|
-
* @instance
|
|
5012
5379
|
* @param {boolean} substringSearch
|
|
5013
5380
|
* @returns {string}
|
|
5014
5381
|
*/
|
|
@@ -5053,8 +5420,6 @@ function requireIpv6 () {
|
|
|
5053
5420
|
/**
|
|
5054
5421
|
* Generate a regular expression that can be used to find or validate all
|
|
5055
5422
|
* variations of this address.
|
|
5056
|
-
* @memberof Address6
|
|
5057
|
-
* @instance
|
|
5058
5423
|
* @param {boolean} substringSearch
|
|
5059
5424
|
* @returns {RegExp}
|
|
5060
5425
|
*/
|
|
@@ -5063,6 +5428,15 @@ function requireIpv6 () {
|
|
|
5063
5428
|
}
|
|
5064
5429
|
}
|
|
5065
5430
|
ipv6.Address6 = Address6;
|
|
5431
|
+
const TYPE_SUBNETS = Object.keys(constants6.TYPES).map((subnet) => [
|
|
5432
|
+
new Address6(subnet),
|
|
5433
|
+
constants6.TYPES[subnet],
|
|
5434
|
+
]);
|
|
5435
|
+
const TEREDO_SUBNET = new Address6('2001::/32');
|
|
5436
|
+
const SIX_TO_FOUR_SUBNET = new Address6('2002::/16');
|
|
5437
|
+
const ULA_SUBNET = new Address6('fc00::/7');
|
|
5438
|
+
const DOCUMENTATION_SUBNET = new Address6('2001:db8::/32');
|
|
5439
|
+
const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96');
|
|
5066
5440
|
|
|
5067
5441
|
return ipv6;
|
|
5068
5442
|
}
|
|
@@ -5072,7 +5446,7 @@ var hasRequiredIpAddress;
|
|
|
5072
5446
|
function requireIpAddress () {
|
|
5073
5447
|
if (hasRequiredIpAddress) return ipAddress;
|
|
5074
5448
|
hasRequiredIpAddress = 1;
|
|
5075
|
-
(function (exports
|
|
5449
|
+
(function (exports) {
|
|
5076
5450
|
var __createBinding = (ipAddress && ipAddress.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5077
5451
|
if (k2 === undefined) k2 = k;
|
|
5078
5452
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -5096,16 +5470,16 @@ function requireIpAddress () {
|
|
|
5096
5470
|
__setModuleDefault(result, mod);
|
|
5097
5471
|
return result;
|
|
5098
5472
|
};
|
|
5099
|
-
Object.defineProperty(exports
|
|
5100
|
-
exports
|
|
5101
|
-
var ipv4_1 = requireIpv4();
|
|
5102
|
-
Object.defineProperty(exports
|
|
5103
|
-
var ipv6_1 = requireIpv6();
|
|
5104
|
-
Object.defineProperty(exports
|
|
5105
|
-
var address_error_1 = requireAddressError();
|
|
5106
|
-
Object.defineProperty(exports
|
|
5107
|
-
const helpers = __importStar(requireHelpers$1());
|
|
5108
|
-
exports
|
|
5473
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5474
|
+
exports.v6 = exports.AddressError = exports.Address6 = exports.Address4 = void 0;
|
|
5475
|
+
var ipv4_1 = /*@__PURE__*/ requireIpv4();
|
|
5476
|
+
Object.defineProperty(exports, "Address4", { enumerable: true, get: function () { return ipv4_1.Address4; } });
|
|
5477
|
+
var ipv6_1 = /*@__PURE__*/ requireIpv6();
|
|
5478
|
+
Object.defineProperty(exports, "Address6", { enumerable: true, get: function () { return ipv6_1.Address6; } });
|
|
5479
|
+
var address_error_1 = /*@__PURE__*/ requireAddressError();
|
|
5480
|
+
Object.defineProperty(exports, "AddressError", { enumerable: true, get: function () { return address_error_1.AddressError; } });
|
|
5481
|
+
const helpers = __importStar(/*@__PURE__*/ requireHelpers$1());
|
|
5482
|
+
exports.v6 = { helpers };
|
|
5109
5483
|
|
|
5110
5484
|
} (ipAddress));
|
|
5111
5485
|
return ipAddress;
|
|
@@ -5121,7 +5495,7 @@ function requireHelpers () {
|
|
|
5121
5495
|
const util_1 = requireUtil();
|
|
5122
5496
|
const constants_1 = requireConstants$2();
|
|
5123
5497
|
const stream = require$$2$1;
|
|
5124
|
-
const ip_address_1 = requireIpAddress();
|
|
5498
|
+
const ip_address_1 = /*@__PURE__*/ requireIpAddress();
|
|
5125
5499
|
const net$1 = net;
|
|
5126
5500
|
/**
|
|
5127
5501
|
* Validates the provided SocksClientOptions
|
|
@@ -5342,7 +5716,7 @@ var hasRequiredSocksclient;
|
|
|
5342
5716
|
function requireSocksclient () {
|
|
5343
5717
|
if (hasRequiredSocksclient) return socksclient;
|
|
5344
5718
|
hasRequiredSocksclient = 1;
|
|
5345
|
-
(function (exports
|
|
5719
|
+
(function (exports) {
|
|
5346
5720
|
var __awaiter = (socksclient && socksclient.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
5347
5721
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5348
5722
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -5352,8 +5726,8 @@ function requireSocksclient () {
|
|
|
5352
5726
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
5353
5727
|
});
|
|
5354
5728
|
};
|
|
5355
|
-
Object.defineProperty(exports
|
|
5356
|
-
exports
|
|
5729
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5730
|
+
exports.SocksClientError = exports.SocksClient = void 0;
|
|
5357
5731
|
const events_1 = require$$0;
|
|
5358
5732
|
const net$1 = net;
|
|
5359
5733
|
const smart_buffer_1 = requireSmartbuffer();
|
|
@@ -5361,8 +5735,8 @@ function requireSocksclient () {
|
|
|
5361
5735
|
const helpers_1 = requireHelpers();
|
|
5362
5736
|
const receivebuffer_1 = requireReceivebuffer();
|
|
5363
5737
|
const util_1 = requireUtil();
|
|
5364
|
-
Object.defineProperty(exports
|
|
5365
|
-
const ip_address_1 = requireIpAddress();
|
|
5738
|
+
Object.defineProperty(exports, "SocksClientError", { enumerable: true, get: function () { return util_1.SocksClientError; } });
|
|
5739
|
+
const ip_address_1 = /*@__PURE__*/ requireIpAddress();
|
|
5366
5740
|
class SocksClient extends events_1.EventEmitter {
|
|
5367
5741
|
constructor(options) {
|
|
5368
5742
|
super();
|
|
@@ -6133,7 +6507,7 @@ function requireSocksclient () {
|
|
|
6133
6507
|
return Object.assign({}, this.options);
|
|
6134
6508
|
}
|
|
6135
6509
|
}
|
|
6136
|
-
exports
|
|
6510
|
+
exports.SocksClient = SocksClient;
|
|
6137
6511
|
|
|
6138
6512
|
} (socksclient));
|
|
6139
6513
|
return socksclient;
|
|
@@ -6144,7 +6518,7 @@ var hasRequiredBuild;
|
|
|
6144
6518
|
function requireBuild () {
|
|
6145
6519
|
if (hasRequiredBuild) return build$1;
|
|
6146
6520
|
hasRequiredBuild = 1;
|
|
6147
|
-
(function (exports
|
|
6521
|
+
(function (exports) {
|
|
6148
6522
|
var __createBinding = (build$1 && build$1.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6149
6523
|
if (k2 === undefined) k2 = k;
|
|
6150
6524
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -6156,11 +6530,11 @@ function requireBuild () {
|
|
|
6156
6530
|
if (k2 === undefined) k2 = k;
|
|
6157
6531
|
o[k2] = m[k];
|
|
6158
6532
|
}));
|
|
6159
|
-
var __exportStar = (build$1 && build$1.__exportStar) || function(m, exports
|
|
6160
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports
|
|
6533
|
+
var __exportStar = (build$1 && build$1.__exportStar) || function(m, exports) {
|
|
6534
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
6161
6535
|
};
|
|
6162
|
-
Object.defineProperty(exports
|
|
6163
|
-
__exportStar(requireSocksclient(), exports
|
|
6536
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6537
|
+
__exportStar(requireSocksclient(), exports);
|
|
6164
6538
|
|
|
6165
6539
|
} (build$1));
|
|
6166
6540
|
return build$1;
|
|
@@ -6504,6 +6878,85 @@ const getCurrentUser = () => {
|
|
|
6504
6878
|
}
|
|
6505
6879
|
};
|
|
6506
6880
|
|
|
6881
|
+
/**
|
|
6882
|
+
* Cookie 工具:把 Set-Cookie 头(或被 `'; '` 拼接污染过的脏 cookie 串)
|
|
6883
|
+
* 归一化为合法的 `Cookie` 请求头值。
|
|
6884
|
+
*
|
|
6885
|
+
* 与浏览器一致的最小行为:
|
|
6886
|
+
* - 丢弃 cookie 属性段(Path / Domain / Max-Age / Expires / Secure / HttpOnly / SameSite / Priority / Partitioned)
|
|
6887
|
+
* - 过滤 `Max-Age <= 0` 或 `Expires` 已过期的 cookie(浏览器不会写入 jar,也就不会发送)
|
|
6888
|
+
* - 保持原有出现顺序,不按 name 去重(浏览器在不同 domain/path 下同名 cookie 会一并发送)
|
|
6889
|
+
*/
|
|
6890
|
+
const COOKIE_ATTRIBUTE_KEYS = new Set([
|
|
6891
|
+
'path',
|
|
6892
|
+
'domain',
|
|
6893
|
+
'max-age',
|
|
6894
|
+
'expires',
|
|
6895
|
+
'secure',
|
|
6896
|
+
'httponly',
|
|
6897
|
+
'samesite',
|
|
6898
|
+
'priority',
|
|
6899
|
+
'partitioned',
|
|
6900
|
+
]);
|
|
6901
|
+
function splitSegments(raw) {
|
|
6902
|
+
return raw
|
|
6903
|
+
.split(';')
|
|
6904
|
+
.map(s => s.trim())
|
|
6905
|
+
.filter(Boolean);
|
|
6906
|
+
}
|
|
6907
|
+
function isAttributeKey(key) {
|
|
6908
|
+
return COOKIE_ATTRIBUTE_KEYS.has(key.toLowerCase());
|
|
6909
|
+
}
|
|
6910
|
+
/**
|
|
6911
|
+
* 清洗任意来源的 Cookie 字符串:
|
|
6912
|
+
* - 兼容标准 `name=value; name=value` 格式(幂等)
|
|
6913
|
+
* - 兼容把多条 Set-Cookie 用 `'; '` 拼接得到的脏串
|
|
6914
|
+
*/
|
|
6915
|
+
function sanitizeCookieHeader(cookieHeader) {
|
|
6916
|
+
if (!cookieHeader)
|
|
6917
|
+
return '';
|
|
6918
|
+
const segments = splitSegments(cookieHeader);
|
|
6919
|
+
const entries = [];
|
|
6920
|
+
let current = null;
|
|
6921
|
+
for (const seg of segments) {
|
|
6922
|
+
const eqIdx = seg.indexOf('=');
|
|
6923
|
+
const key = (eqIdx < 0 ? seg : seg.slice(0, eqIdx)).trim();
|
|
6924
|
+
const val = eqIdx < 0 ? '' : seg.slice(eqIdx + 1).trim();
|
|
6925
|
+
if (!key)
|
|
6926
|
+
continue;
|
|
6927
|
+
if (isAttributeKey(key)) {
|
|
6928
|
+
if (!current)
|
|
6929
|
+
continue;
|
|
6930
|
+
const lk = key.toLowerCase();
|
|
6931
|
+
if (lk === 'max-age') {
|
|
6932
|
+
const n = Number(val);
|
|
6933
|
+
if (Number.isFinite(n) && n <= 0)
|
|
6934
|
+
current.expired = true;
|
|
6935
|
+
}
|
|
6936
|
+
else if (lk === 'expires') {
|
|
6937
|
+
const t = Date.parse(val);
|
|
6938
|
+
if (!Number.isNaN(t) && t <= Date.now())
|
|
6939
|
+
current.expired = true;
|
|
6940
|
+
}
|
|
6941
|
+
continue;
|
|
6942
|
+
}
|
|
6943
|
+
current = { name: key, value: val, expired: false };
|
|
6944
|
+
entries.push(current);
|
|
6945
|
+
}
|
|
6946
|
+
return entries
|
|
6947
|
+
.filter(e => !e.expired)
|
|
6948
|
+
.map(e => `${e.name}=${e.value}`)
|
|
6949
|
+
.join('; ');
|
|
6950
|
+
}
|
|
6951
|
+
/**
|
|
6952
|
+
* 从 `response.headers['set-cookie']` 数组构建可用于 `Cookie` 请求头的字符串。
|
|
6953
|
+
*/
|
|
6954
|
+
function buildCookieHeaderFromSetCookies(setCookies) {
|
|
6955
|
+
if (!setCookies || setCookies.length === 0)
|
|
6956
|
+
return '';
|
|
6957
|
+
return sanitizeCookieHeader(setCookies.join('; '));
|
|
6958
|
+
}
|
|
6959
|
+
|
|
6507
6960
|
function isVerboseEnabled() {
|
|
6508
6961
|
return process.argv.includes('--verbose');
|
|
6509
6962
|
}
|
|
@@ -6654,7 +7107,7 @@ function printApiResponseLog(title, result) {
|
|
|
6654
7107
|
}
|
|
6655
7108
|
async function request({ url, method, data, headers, params, }) {
|
|
6656
7109
|
const config = getTTMGRC();
|
|
6657
|
-
const cookie = config?.cookie;
|
|
7110
|
+
const cookie = sanitizeCookieHeader(config?.cookie);
|
|
6658
7111
|
const proxyConfig = getAxiosProxyConfig();
|
|
6659
7112
|
if (isVerboseEnabled()) {
|
|
6660
7113
|
printApiRequestLog({
|
|
@@ -11541,10 +11994,13 @@ async function login(options) {
|
|
|
11541
11994
|
process.exit(1);
|
|
11542
11995
|
}
|
|
11543
11996
|
else {
|
|
11997
|
+
const setCookies = response?.headers['set-cookie'];
|
|
11998
|
+
const cookie = buildCookieHeaderFromSetCookies(setCookies);
|
|
11999
|
+
log('Parsed cookies', { rawCount: setCookies?.length ?? 0, kept: cookie ? cookie.split('; ').length : 0 });
|
|
11544
12000
|
const loginData = {
|
|
11545
12001
|
email,
|
|
11546
12002
|
user_id: response?.data?.data?.user_id,
|
|
11547
|
-
cookie
|
|
12003
|
+
cookie,
|
|
11548
12004
|
};
|
|
11549
12005
|
log('Login success', { user_id: loginData.user_id, email: loginData.email });
|
|
11550
12006
|
setTTMGRC(loginData);
|
|
@@ -11818,7 +12274,7 @@ async function upload({ clientKey, note = '--', dir, }) {
|
|
|
11818
12274
|
}
|
|
11819
12275
|
}
|
|
11820
12276
|
|
|
11821
|
-
var version = "0.3.8-beta.
|
|
12277
|
+
var version = "0.3.8-beta.3";
|
|
11822
12278
|
var pkg = {
|
|
11823
12279
|
version: version};
|
|
11824
12280
|
|