Skip to content

Commit 05bd2a4

Browse files
martinrrmCopilot
andcommitted
deps: ip-address@10.5.0
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 73e1dfa8-6bec-47aa-b811-4edf404e9883
1 parent b7c490d commit 05bd2a4

7 files changed

Lines changed: 309 additions & 107 deletions

File tree

node_modules/ip-address/dist/common.js

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,47 @@
11
"use strict";
22
Object.defineProperty(exports, "__esModule", { value: true });
33
exports.isInSubnet = isInSubnet;
4+
exports.isHostInSubnet = isHostInSubnet;
45
exports.isCorrect = isCorrect;
56
exports.prefixLengthFromMask = prefixLengthFromMask;
7+
exports.assertByteArray = assertByteArray;
68
exports.numberToPaddedHex = numberToPaddedHex;
79
exports.stringToPaddedHex = stringToPaddedHex;
810
exports.testBit = testBit;
911
const address_error_1 = require("./address-error");
12+
/**
13+
* Returns whether this address's *network* is contained within `address`,
14+
* i.e. whether every address this one can represent also falls inside
15+
* `address`. A network wider than `address` is not contained in it, so
16+
* `10.0.0.0/8` is not in `10.0.0.0/16`.
17+
*
18+
* To ask whether the address itself falls inside a range, ignoring any CIDR
19+
* suffix it was written with, use {@link isHostInSubnet} instead. That is the
20+
* question the special-use classifiers ask.
21+
*/
1022
function isInSubnet(address) {
1123
if (this.subnetMask < address.subnetMask) {
1224
return false;
1325
}
14-
if (this.mask(address.subnetMask) === address.mask()) {
15-
return true;
16-
}
17-
return false;
26+
return isHostInSubnet.call(this, address);
27+
}
28+
/**
29+
* Returns whether this address's host bits fall inside `address`, ignoring
30+
* this address's own subnet mask.
31+
*
32+
* This is the primitive the special-use classifiers (`isLoopback`,
33+
* `isPrivate`, `isLinkLocal`, `getType`, …) are built on: they answer a
34+
* question about the address, so the answer must not change with the CIDR
35+
* suffix the caller happened to write. Use this rather than
36+
* {@link isInSubnet} when classifying a single address — notably when the
37+
* address came from untrusted input and the result backs a trust-boundary
38+
* decision such as an SSRF allow/deny filter.
39+
*/
40+
function isHostInSubnet(address) {
41+
return this.mask(address.subnetMask) === address.mask();
1842
}
1943
function isCorrect(defaultBits) {
20-
return function () {
44+
return function isCorrectForm() {
2145
if (this.addressMinusSuffix !== this.correctForm()) {
2246
return false;
2347
}
@@ -46,6 +70,21 @@ function prefixLengthFromMask(value, totalBits) {
4670
}
4771
return firstZero;
4872
}
73+
/**
74+
* Throws `AddressError` unless `bytes` holds exactly `byteCount` integers,
75+
* each from `minimum` to 255. Pass a `minimum` of `-128` where signed bytes
76+
* are accepted and folded to unsigned, and `0` where they are not.
77+
*/
78+
function assertByteArray(bytes, byteCount, family, minimum) {
79+
if (bytes.length !== byteCount) {
80+
throw new address_error_1.AddressError(`${family} addresses require exactly ${byteCount} bytes`);
81+
}
82+
for (let i = 0; i < bytes.length; i++) {
83+
if (!Number.isInteger(bytes[i]) || bytes[i] < minimum || bytes[i] > 255) {
84+
throw new address_error_1.AddressError(`All bytes must be integers between ${minimum} and 255`);
85+
}
86+
}
87+
}
4988
function numberToPaddedHex(number) {
5089
return number.toString(16).padStart(2, '0');
5190
}

node_modules/ip-address/dist/ipv4.js

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const isCorrect4 = common.isCorrect(constants.BITS);
3535
*/
3636
class Address4 {
3737
constructor(address) {
38+
this.addressMinusSuffix = '';
3839
this.groups = constants.GROUPS;
3940
this.parsedAddress = [];
4041
this.parsedSubnet = '';
@@ -51,6 +52,15 @@ class Address4 {
5152
* @returns {boolean}
5253
*/
5354
this.isInSubnet = common.isInSubnet;
55+
/**
56+
* Returns true if this address's host bits fall inside the given subnet,
57+
* ignoring this address's own subnet mask. Prefer this over `isInSubnet`
58+
* when classifying a single address, so the answer doesn't change with the
59+
* CIDR suffix the caller happened to write — notably when the address came
60+
* from untrusted input and the result backs a trust-boundary decision.
61+
* @returns {boolean}
62+
*/
63+
this.isHostInSubnet = common.isHostInSubnet;
5464
this.address = address;
5565
const subnet = constants.RE_SUBNET_STRING.exec(address);
5666
if (subnet) {
@@ -78,7 +88,7 @@ class Address4 {
7888
new Address4(address);
7989
return true;
8090
}
81-
catch (e) {
91+
catch {
8292
return false;
8393
}
8494
}
@@ -90,6 +100,11 @@ class Address4 {
90100
*/
91101
parse(address) {
92102
const groups = address.split('.');
103+
// Checked before the general match so the error names the actual problem.
104+
// Address6 rejects the same notation on its v4-in-v6 path.
105+
if (groups.some((group) => /^0\d/.test(group))) {
106+
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.");
107+
}
93108
if (!address.match(constants.RE_ADDRESS)) {
94109
throw new address_error_1.AddressError('Invalid IPv4 address.');
95110
}
@@ -128,7 +143,6 @@ class Address4 {
128143
static fromAddressAndWildcardMask(address, wildcardMask) {
129144
const wildcard = new Address4(wildcardMask).bigInt();
130145
const allOnes = (BigInt(1) << BigInt(constants.BITS)) - BigInt(1);
131-
// eslint-disable-next-line no-bitwise
132146
const mask = wildcard ^ allOnes;
133147
const bits = common.prefixLengthFromMask(mask, constants.BITS);
134148
return new Address4(`${address}/${bits}`);
@@ -328,32 +342,32 @@ class Address4 {
328342
* @returns {Address4}
329343
*/
330344
static fromBigInt(bigInt) {
331-
if (bigInt < 0n || bigInt > 0xffffffffn) {
345+
if (bigInt < BigInt(0) || bigInt > BigInt(0xffffffff)) {
332346
throw new address_error_1.AddressError('IPv4 BigInt must be in the range 0 to 2**32 - 1');
333347
}
334348
return Address4.fromHex(bigInt.toString(16).padStart(8, '0'));
335349
}
336350
/**
337-
* Convert a byte array to an Address4 object.
351+
* Convert a byte array to an Address4 object. Throws `AddressError` unless
352+
* given exactly 4 integers from 0 to 255. Signed bytes are rejected, so
353+
* this differs from `Address6.fromByteArray`, which folds them; the two
354+
* contracts converge on this stricter form in the next major version.
338355
*
339356
* To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`.
340357
* @param {Array<number>} bytes - an array of 4 bytes (0-255)
341358
* @returns {Address4}
342359
*/
343360
static fromByteArray(bytes) {
344-
if (bytes.length !== 4) {
345-
throw new address_error_1.AddressError('IPv4 addresses require exactly 4 bytes');
346-
}
347-
// Validate that all bytes are within valid range (0-255)
348-
for (let i = 0; i < bytes.length; i++) {
349-
if (!Number.isInteger(bytes[i]) || bytes[i] < 0 || bytes[i] > 255) {
350-
throw new address_error_1.AddressError('All bytes must be integers between 0 and 255');
351-
}
352-
}
361+
common.assertByteArray(bytes, 4, 'IPv4', 0);
353362
return this.fromUnsignedByteArray(bytes);
354363
}
355364
/**
356-
* Convert an unsigned byte array to an Address4 object
365+
* Convert an unsigned byte array to an Address4 object. Throws
366+
* `AddressError` unless given exactly 4 bytes, and rejects values outside
367+
* 0 to 255 when parsing the resulting address.
368+
*
369+
* To convert from a Node.js `Buffer`, spread it:
370+
* `Address4.fromUnsignedByteArray([...buf])`.
357371
* @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
358372
* @returns {Address4}
359373
*/
@@ -383,7 +397,8 @@ class Address4 {
383397
return this.binaryZeroPad().slice(start, end);
384398
}
385399
/**
386-
* Return the reversed ip6.arpa form of the address
400+
* Return the reversed in-addr.arpa form of the address, e.g.
401+
* `42.2.0.192.in-addr.arpa.` for `192.0.2.42`.
387402
* @param {Object} options
388403
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
389404
* @returns {String}
@@ -403,49 +418,49 @@ class Address4 {
403418
* @returns {boolean}
404419
*/
405420
isMulticast() {
406-
return this.isInSubnet(MULTICAST_V4);
421+
return this.isHostInSubnet(MULTICAST_V4);
407422
}
408423
/**
409424
* 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`).
410425
* @returns {boolean}
411426
*/
412427
isPrivate() {
413-
return PRIVATE_V4.some((subnet) => this.isInSubnet(subnet));
428+
return PRIVATE_V4.some((subnet) => this.isHostInSubnet(subnet));
414429
}
415430
/**
416431
* Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)).
417432
* @returns {boolean}
418433
*/
419434
isLoopback() {
420-
return this.isInSubnet(LOOPBACK_V4);
435+
return this.isHostInSubnet(LOOPBACK_V4);
421436
}
422437
/**
423438
* 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)).
424439
* @returns {boolean}
425440
*/
426441
isLinkLocal() {
427-
return this.isInSubnet(LINK_LOCAL_V4);
442+
return this.isHostInSubnet(LINK_LOCAL_V4);
428443
}
429444
/**
430445
* Returns true if the address is the unspecified address `0.0.0.0`.
431446
* @returns {boolean}
432447
*/
433448
isUnspecified() {
434-
return this.isInSubnet(UNSPECIFIED_V4);
449+
return this.isHostInSubnet(UNSPECIFIED_V4);
435450
}
436451
/**
437452
* Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)).
438453
* @returns {boolean}
439454
*/
440455
isBroadcast() {
441-
return this.isInSubnet(BROADCAST_V4);
456+
return this.isHostInSubnet(BROADCAST_V4);
442457
}
443458
/**
444459
* 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)).
445460
* @returns {boolean}
446461
*/
447462
isCGNAT() {
448-
return this.isInSubnet(CGNAT_V4);
463+
return this.isHostInSubnet(CGNAT_V4);
449464
}
450465
/**
451466
* Returns a zero-padded base-2 string representation of the address
@@ -458,12 +473,17 @@ class Address4 {
458473
return this._binaryZeroPad;
459474
}
460475
/**
461-
* Groups an IPv4 address for inclusion at the end of an IPv6 address
476+
* Groups an IPv4 address for inclusion at the end of an IPv6 address.
477+
*
478+
* Returns an HTML fragment: each half of the address is wrapped in a
479+
* `<span>` carrying the group classes an address-inspector UI hovers on.
480+
* The address content is HTML-escaped; anything you concatenate around it
481+
* is your responsibility.
462482
* @returns {String}
463483
*/
464484
groupForV6() {
465485
const segments = this.parsedAddress;
466-
return this.address.replace(constants.RE_ADDRESS, `<span class="hover-group group-v4 group-6">${segments
486+
return this.correctForm().replace(constants.RE_ADDRESS, `<span class="hover-group group-v4 group-6">${segments
467487
.slice(0, 2)
468488
.join('.')}</span>.<span class="hover-group group-v4 group-7">${segments
469489
.slice(2, 4)

0 commit comments

Comments
 (0)