@nullix/zod-mongoose-studio 3.2.0 → 3.3.1
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/.output/nitro.json +1 -1
- package/.output/public/_fonts/57NSSoFy1VLVs2gqly8Ls9awBnZMFyXGrefpmqvdqmc-zJfbBtpgM4cDmcXBsqZNW79_kFnlpPd62b48glgdydA.woff2 +0 -0
- package/.output/public/_fonts/8VR2wSMN-3U4NbWAVYXlkRV6hA0jFBXP-0RtL3X7fko-x2gYI4qfmkRdxyQQUPaBZdZdgl1TeVrquF_TxHeM4lM.woff2 +0 -0
- package/.output/public/_fonts/GsKUclqeNLJ96g5AU593ug6yanivOiwjW_7zESNPChw-jHA4tBeM1bjF7LATGUpfBuSTyomIFrWBTzjF7txVYfg.woff2 +0 -0
- package/.output/public/_fonts/Ld1FnTo3yTIwDyGfTQ5-Fws9AWsCbKfMvgxduXr7JcY-W25bL8NF1fjpLRSOgJb7RoZPHqGQNwMTM7S9tHVoxx8.woff2 +0 -0
- package/.output/public/_fonts/NdzqRASp2bovDUhQT1IRE_EMqKJ2KYQdTCfFcBvL8yw-KhwZiS86o3fErOe5GGMExHUemmI_dBfaEFxjISZrBd0.woff2 +0 -0
- package/.output/public/_fonts/iTkrULNFJJkTvihIg1Vqi5IODRH_9btXCioVF5l98I8-AndUyau2HR2felA_ra8V2mutQgschhasE5FD1dXGJX8.woff2 +0 -0
- package/.output/public/_nuxt/{qQyvCkbV.js → 5Tu2WUJz.js} +1 -1
- package/.output/public/_nuxt/B0N6xv5E.js +1 -0
- package/.output/public/_nuxt/{DjPT-NCE.js → B0cUlOSM.js} +1 -1
- package/.output/public/_nuxt/B9paGgN0.js +33 -0
- package/.output/public/_nuxt/{IxYCG8hB.js → BCIlnd0g.js} +1 -1
- package/.output/public/_nuxt/{ikxafTHA.js → BNDnV2op.js} +180 -184
- package/.output/public/_nuxt/{Ce-T_1aD.js → BO4hqv6q.js} +1 -1
- package/.output/public/_nuxt/{Bd32GOUy.js → BOsJJ_ZU.js} +1 -1
- package/.output/public/_nuxt/{BzhSDy30.js → C2BHp-MG.js} +1 -1
- package/.output/public/_nuxt/{Cs8GXJCB.js → CKULsFUz.js} +1 -1
- package/.output/public/_nuxt/CMH9iX_E.js +6 -0
- package/.output/public/_nuxt/{tzj4nvDE.js → CzbCpNnc.js} +2 -2
- package/.output/public/_nuxt/{CC3n3Aga.js → D87QMS6j.js} +1 -1
- package/.output/public/_nuxt/DA0pQuyP.js +27 -0
- package/.output/public/_nuxt/{B7P0wQ35.js → DcJ7oPvZ.js} +1 -1
- package/.output/public/_nuxt/{Ick_23I4.js → Dce9SnGa.js} +1 -1
- package/.output/public/_nuxt/{CAd-qHfI.js → DpKrXpkK.js} +1 -1
- package/.output/public/_nuxt/DsnIpnT9.js +1 -0
- package/.output/public/_nuxt/{CNZorjDf.js → I3Ucam2s.js} +1 -1
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/51f1351c-0667-4235-9ddc-16582a51ce03.json +1 -0
- package/.output/public/_nuxt/{entry.J_CbC0oY.css → entry.B-vs1tRH.css} +1 -1
- package/.output/public/_nuxt/error-404.CTSXlFYa.css +1 -0
- package/.output/public/_nuxt/error-500.DqEfQnVZ.css +1 -0
- package/.output/public/_nuxt/{nDZOJ7rN.js → o-NCh2rp.js} +2 -2
- package/.output/public/_nuxt/{qwxNOyg7.js → sKEJiAHO.js} +1 -1
- package/.output/public/_nuxt/{81vqh61j.js → tqQNlhT9.js} +1 -1
- package/.output/public/_nuxt/ypRHVLFO.js +1 -0
- package/.output/server/chunks/_/error-500.mjs.map +1 -1
- package/.output/server/chunks/build/client.precomputed.mjs +1 -1
- package/.output/server/chunks/build/{error-404-BN-7rNE4.mjs → error-404-KRkA0DPI.mjs} +10 -4
- package/.output/server/chunks/build/error-404-KRkA0DPI.mjs.map +1 -0
- package/.output/server/chunks/build/error-404-styles.I0NYw-Bn.mjs +8 -0
- package/.output/server/chunks/build/error-404-styles.I0NYw-Bn.mjs.map +1 -0
- package/.output/server/chunks/build/{error-500-DhIQ-2yt.mjs → error-500-DIIFf55p.mjs} +10 -4
- package/.output/server/chunks/build/error-500-DIIFf55p.mjs.map +1 -0
- package/.output/server/chunks/build/error-500-styles.D1cs9hQy.mjs +8 -0
- package/.output/server/chunks/build/error-500-styles.D1cs9hQy.mjs.map +1 -0
- package/.output/server/chunks/build/index-CB1N4gax.mjs +557 -0
- package/.output/server/chunks/build/index-CB1N4gax.mjs.map +1 -0
- package/.output/server/chunks/build/server.mjs +326 -248
- package/.output/server/chunks/build/server.mjs.map +1 -1
- package/.output/server/chunks/build/styles.mjs +4 -4
- package/.output/server/chunks/nitro/nitro.mjs +2302 -835
- package/.output/server/chunks/nitro/nitro.mjs.map +1 -1
- package/.output/server/chunks/routes/api/editor-types.get.mjs +44 -0
- package/.output/server/chunks/routes/api/editor-types.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/parse.post.mjs +26 -1316
- package/.output/server/chunks/routes/api/parse.post.mjs.map +1 -1
- package/.output/server/chunks/routes/api/resolve.get.mjs +6 -0
- package/.output/server/chunks/routes/api/resolve.get.mjs.map +1 -1
- package/.output/server/chunks/routes/api/studio/run.post.mjs +35 -0
- package/.output/server/chunks/routes/api/studio/run.post.mjs.map +1 -0
- package/.output/server/chunks/routes/renderer.mjs +1 -1
- package/.output/server/chunks/routes/renderer.mjs.map +1 -1
- package/.output/server/index.mjs +7 -1
- package/.output/server/index.mjs.map +1 -1
- package/.output/server/node_modules/acorn/dist/acorn.mjs +6266 -0
- package/.output/server/node_modules/acorn/package.json +50 -0
- package/.output/server/node_modules/ip-address/dist/common.js +112 -4
- package/.output/server/node_modules/ip-address/dist/ipv4.js +322 -87
- package/.output/server/node_modules/ip-address/dist/ipv6.js +654 -199
- package/.output/server/node_modules/ip-address/dist/v4/constants.js +45 -2
- package/.output/server/node_modules/ip-address/dist/v6/constants.js +55 -3
- package/.output/server/node_modules/ip-address/dist/v6/helpers.js +12 -3
- package/.output/server/node_modules/ip-address/package.json +49 -37
- package/.output/server/node_modules/ufo/dist/index.mjs +2 -2
- package/.output/server/node_modules/ufo/package.json +9 -9
- package/.output/server/package.json +4 -3
- package/README.md +62 -19
- package/app/assets/css/main.css +1 -0
- package/app/assets/css/studio.css +131 -0
- package/app/components/StudioConversion.vue +41 -0
- package/app/components/StudioDataPanel.vue +21 -0
- package/app/components/StudioEditor.vue +78 -102
- package/app/components/StudioExpandButton.vue +11 -0
- package/app/components/StudioOutput.vue +7 -1
- package/app/components/StudioSourcePanel.vue +16 -0
- package/app/components/StudioValidation.vue +47 -0
- package/app/components/ZodMongooseStudio.vue +216 -198
- package/app/composables/useStudioRunner.ts +142 -0
- package/app/pages/index.vue +1 -1
- package/app/plugins/monaco.client.ts +2 -0
- package/bin/index.mjs +5 -0
- package/nuxt.config.ts +4 -3
- package/package.json +4 -2
- package/server/api/editor-types.get.ts +28 -0
- package/server/api/parse.post.ts +17 -175
- package/server/api/studio/run.post.ts +17 -0
- package/server/middleware/security.ts +29 -7
- package/server/utils/example-data.ts +80 -0
- package/server/utils/parse-request.ts +28 -0
- package/server/utils/runner-client.ts +40 -0
- package/server/utils/studio-execution.ts +176 -0
- package/.output/public/_nuxt/BD40YYqZ.js +0 -33
- package/.output/public/_nuxt/BlQmLjV4.js +0 -1
- package/.output/public/_nuxt/CJ4Cv9fY.js +0 -61
- package/.output/public/_nuxt/builds/meta/34871c14-b0f4-4898-9ff0-debaff743355.json +0 -1
- package/.output/public/_nuxt/error-404.64pZEiDn.css +0 -1
- package/.output/public/_nuxt/error-500.DHOpI0Ir.css +0 -1
- package/.output/public/_nuxt/rH_O4qXT.js +0 -1
- package/.output/server/chunks/build/error-404-BN-7rNE4.mjs.map +0 -1
- package/.output/server/chunks/build/error-404-styles.Byx46oLR.mjs +0 -8
- package/.output/server/chunks/build/error-404-styles.Byx46oLR.mjs.map +0 -1
- package/.output/server/chunks/build/error-500-DhIQ-2yt.mjs.map +0 -1
- package/.output/server/chunks/build/error-500-styles.BL3UT0Wa.mjs +0 -8
- package/.output/server/chunks/build/error-500-styles.BL3UT0Wa.mjs.map +0 -1
- package/.output/server/chunks/build/index-B4T6zHp0.mjs +0 -1904
- package/.output/server/chunks/build/index-B4T6zHp0.mjs.map +0 -1
- package/.output/server/node_modules/zod/index.js +0 -4
- /package/.output/public/_nuxt/{editor.CdBKkuhR.css → monaco.CdBKkuhR.css} +0 -0
|
@@ -28,13 +28,14 @@ exports.Address4 = void 0;
|
|
|
28
28
|
const common = __importStar(require("./common"));
|
|
29
29
|
const constants = __importStar(require("./v4/constants"));
|
|
30
30
|
const address_error_1 = require("./address-error");
|
|
31
|
+
const isCorrect4 = common.isCorrect(constants.BITS);
|
|
31
32
|
/**
|
|
32
33
|
* Represents an IPv4 address
|
|
33
|
-
* @class Address4
|
|
34
34
|
* @param {string} address - An IPv4 address string
|
|
35
35
|
*/
|
|
36
36
|
class Address4 {
|
|
37
37
|
constructor(address) {
|
|
38
|
+
this.addressMinusSuffix = '';
|
|
38
39
|
this.groups = constants.GROUPS;
|
|
39
40
|
this.parsedAddress = [];
|
|
40
41
|
this.parsedSubnet = '';
|
|
@@ -43,18 +44,27 @@ class Address4 {
|
|
|
43
44
|
this.v4 = true;
|
|
44
45
|
/**
|
|
45
46
|
* Returns true if the address is correct, false otherwise
|
|
46
|
-
* @memberof Address4
|
|
47
|
-
* @instance
|
|
48
47
|
* @returns {Boolean}
|
|
49
48
|
*/
|
|
50
|
-
this.isCorrect =
|
|
49
|
+
this.isCorrect = isCorrect4;
|
|
51
50
|
/**
|
|
52
|
-
* Returns true if the given address is in the subnet of the current address
|
|
53
|
-
*
|
|
54
|
-
*
|
|
51
|
+
* Returns true if the given address is in the subnet of the current address.
|
|
52
|
+
* An `Address6` is never in the subnet of an `Address4`; convert with
|
|
53
|
+
* `to4()` or `Address6.fromAddress4()` to compare across families.
|
|
55
54
|
* @returns {boolean}
|
|
56
55
|
*/
|
|
57
56
|
this.isInSubnet = common.isInSubnet;
|
|
57
|
+
/**
|
|
58
|
+
* Returns true if this address's host bits fall inside the given subnet,
|
|
59
|
+
* ignoring this address's own subnet mask. Prefer this over `isInSubnet`
|
|
60
|
+
* when classifying a single address, so the answer doesn't change with the
|
|
61
|
+
* CIDR suffix the caller happened to write — notably when the address came
|
|
62
|
+
* from untrusted input and the result backs a trust-boundary decision.
|
|
63
|
+
* An `Address6` is never in the subnet of an `Address4`; convert with
|
|
64
|
+
* `to4()` or `Address6.fromAddress4()` to compare across families.
|
|
65
|
+
* @returns {boolean}
|
|
66
|
+
*/
|
|
67
|
+
this.isHostInSubnet = common.isHostInSubnet;
|
|
58
68
|
this.address = address;
|
|
59
69
|
const subnet = constants.RE_SUBNET_STRING.exec(address);
|
|
60
70
|
if (subnet) {
|
|
@@ -66,94 +76,182 @@ class Address4 {
|
|
|
66
76
|
}
|
|
67
77
|
address = address.replace(constants.RE_SUBNET_STRING, '');
|
|
68
78
|
}
|
|
79
|
+
// Four three-digit octets and three dots: the longest well-formed address
|
|
80
|
+
// is 15 characters. Longer input is rejected before parsing, as Address6
|
|
81
|
+
// does at its own limit.
|
|
82
|
+
const longest = constants.GROUPS * 4 - 1;
|
|
83
|
+
if (address.length > longest) {
|
|
84
|
+
throw new address_error_1.AddressError(`IPv4 addresses are at most ${longest} characters.`);
|
|
85
|
+
}
|
|
69
86
|
this.addressMinusSuffix = address;
|
|
70
87
|
this.parsedAddress = this.parse(address);
|
|
71
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Returns true if the given string is a valid IPv4 address (with optional
|
|
91
|
+
* CIDR subnet), false otherwise. Host bits in the subnet portion are
|
|
92
|
+
* allowed (e.g. `192.168.1.5/24` is valid); for strict network-address
|
|
93
|
+
* validation compare `correctForm()` to `startAddress().correctForm()`,
|
|
94
|
+
* or use `networkForm()`.
|
|
95
|
+
*/
|
|
72
96
|
static isValid(address) {
|
|
73
97
|
try {
|
|
74
98
|
// eslint-disable-next-line no-new
|
|
75
99
|
new Address4(address);
|
|
76
100
|
return true;
|
|
77
101
|
}
|
|
78
|
-
catch
|
|
102
|
+
catch {
|
|
79
103
|
return false;
|
|
80
104
|
}
|
|
81
105
|
}
|
|
82
|
-
|
|
83
|
-
* Parses
|
|
106
|
+
/**
|
|
107
|
+
* Parses an IPv4 address string into its four octet groups and stores the
|
|
108
|
+
* result on `this.parsedAddress`. Called automatically by the constructor;
|
|
109
|
+
* you typically don't need to call it directly. Throws `AddressError` if
|
|
110
|
+
* the input is not a valid IPv4 address.
|
|
84
111
|
*/
|
|
85
112
|
parse(address) {
|
|
86
113
|
const groups = address.split('.');
|
|
114
|
+
// Checked before the general match so the error names the actual problem.
|
|
115
|
+
// Address6 rejects the same notation on its v4-in-v6 path.
|
|
116
|
+
if (groups.some((group) => /^0\d/.test(group))) {
|
|
117
|
+
throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.");
|
|
118
|
+
}
|
|
87
119
|
if (!address.match(constants.RE_ADDRESS)) {
|
|
88
120
|
throw new address_error_1.AddressError('Invalid IPv4 address.');
|
|
89
121
|
}
|
|
90
122
|
return groups;
|
|
91
123
|
}
|
|
92
124
|
/**
|
|
93
|
-
* Returns the correct form
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* @returns {String}
|
|
125
|
+
* Returns the address in correct form: octets joined with `.` and any
|
|
126
|
+
* leading zeros stripped (e.g. `192.168.1.1`). For IPv4 this matches the
|
|
127
|
+
* canonical dotted-decimal representation.
|
|
97
128
|
*/
|
|
98
129
|
correctForm() {
|
|
99
130
|
return this.parsedAddress.map((part) => parseInt(part, 10)).join('.');
|
|
100
131
|
}
|
|
101
132
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
133
|
+
* Construct an `Address4` from an address and a dotted-decimal subnet
|
|
134
|
+
* mask given as separate strings (e.g. as returned by Node's
|
|
135
|
+
* `os.networkInterfaces()`). Throws `AddressError` if the mask is
|
|
136
|
+
* non-contiguous (e.g. `255.0.255.0`).
|
|
137
|
+
* @example
|
|
138
|
+
* var address = Address4.fromAddressAndMask('192.168.1.1', '255.255.255.0');
|
|
139
|
+
* address.subnetMask; // 24
|
|
140
|
+
*/
|
|
141
|
+
static fromAddressAndMask(address, mask) {
|
|
142
|
+
const bits = common.prefixLengthFromMask(new Address4(mask).bigInt(), constants.BITS);
|
|
143
|
+
return new Address4(`${address}/${bits}`);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Construct an `Address4` from an address and a Cisco-style wildcard mask
|
|
147
|
+
* given as separate strings (e.g. `0.0.0.255` for a `/24`). The wildcard
|
|
148
|
+
* mask is the bitwise inverse of the subnet mask. Throws `AddressError`
|
|
149
|
+
* if the mask is non-contiguous (e.g. `0.255.0.255`).
|
|
150
|
+
* @example
|
|
151
|
+
* var address = Address4.fromAddressAndWildcardMask('10.0.0.1', '0.0.0.255');
|
|
152
|
+
* address.subnetMask; // 24
|
|
153
|
+
*/
|
|
154
|
+
static fromAddressAndWildcardMask(address, wildcardMask) {
|
|
155
|
+
const wildcard = new Address4(wildcardMask).bigInt();
|
|
156
|
+
const allOnes = (BigInt(1) << BigInt(constants.BITS)) - BigInt(1);
|
|
157
|
+
const mask = wildcard ^ allOnes;
|
|
158
|
+
const bits = common.prefixLengthFromMask(mask, constants.BITS);
|
|
159
|
+
return new Address4(`${address}/${bits}`);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Construct an `Address4` from a wildcard pattern with trailing `*`
|
|
163
|
+
* octets. The number of trailing wildcards determines the prefix
|
|
164
|
+
* length: each `*` represents 8 bits.
|
|
165
|
+
*
|
|
166
|
+
* Only trailing whole-octet wildcards are supported. Partial-octet
|
|
167
|
+
* wildcards (e.g. `192.168.0.1*`) and interior wildcards (e.g.
|
|
168
|
+
* `192.*.0.1`) throw `AddressError`.
|
|
169
|
+
* @example
|
|
170
|
+
* Address4.fromWildcard('192.168.0.*').subnet; // '/24'
|
|
171
|
+
* Address4.fromWildcard('192.168.*.*').subnet; // '/16'
|
|
172
|
+
* Address4.fromWildcard('*.*.*.*').subnet; // '/0'
|
|
173
|
+
*/
|
|
174
|
+
static fromWildcard(input) {
|
|
175
|
+
const groups = input.split('.');
|
|
176
|
+
if (groups.length !== constants.GROUPS) {
|
|
177
|
+
throw new address_error_1.AddressError('Wildcard pattern must have 4 octets');
|
|
178
|
+
}
|
|
179
|
+
let firstWildcard = -1;
|
|
180
|
+
for (let i = 0; i < groups.length; i++) {
|
|
181
|
+
if (groups[i] === '*') {
|
|
182
|
+
if (firstWildcard === -1) {
|
|
183
|
+
firstWildcard = i;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else if (firstWildcard !== -1) {
|
|
187
|
+
throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing octets (e.g. `192.168.0.*`)');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
|
|
191
|
+
const replaced = groups.map((g) => (g === '*' ? '0' : g));
|
|
192
|
+
const subnetBits = constants.BITS - trailing * 8;
|
|
193
|
+
return new Address4(`${replaced.join('.')}/${subnetBits}`);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Converts a hex string to an IPv4 address object. Accepts 8 hex digits
|
|
197
|
+
* with optional `:` separators (e.g. `'7f000001'` or `'7f:00:00:01'`).
|
|
198
|
+
* Throws `AddressError` for any other length or for non-hex characters.
|
|
105
199
|
* @param {string} hex - a hex string to convert
|
|
106
200
|
* @returns {Address4}
|
|
107
201
|
*/
|
|
108
202
|
static fromHex(hex) {
|
|
109
|
-
const
|
|
203
|
+
const stripped = hex.replace(/:/g, '');
|
|
204
|
+
if (!/^[0-9a-fA-F]{8}$/.test(stripped)) {
|
|
205
|
+
throw new address_error_1.AddressError('IPv4 hex must be exactly 8 hex digits');
|
|
206
|
+
}
|
|
110
207
|
const groups = [];
|
|
111
|
-
let i;
|
|
112
|
-
|
|
113
|
-
const h = padded.slice(i, i + 2);
|
|
114
|
-
groups.push(parseInt(h, 16));
|
|
208
|
+
for (let i = 0; i < 8; i += 2) {
|
|
209
|
+
groups.push(parseInt(stripped.slice(i, i + 2), 16));
|
|
115
210
|
}
|
|
116
211
|
return new Address4(groups.join('.'));
|
|
117
212
|
}
|
|
118
213
|
/**
|
|
119
|
-
* Converts an integer into a IPv4 address object
|
|
120
|
-
*
|
|
121
|
-
*
|
|
214
|
+
* Converts an integer into a IPv4 address object. The integer must be a
|
|
215
|
+
* non-negative safe integer in the range `[0, 2**32 - 1]`; otherwise
|
|
216
|
+
* `AddressError` is thrown.
|
|
122
217
|
* @param {integer} integer - a number to convert
|
|
123
218
|
* @returns {Address4}
|
|
124
219
|
*/
|
|
125
220
|
static fromInteger(integer) {
|
|
126
|
-
|
|
221
|
+
if (!Number.isInteger(integer) || integer < 0 || integer > 0xffffffff) {
|
|
222
|
+
throw new address_error_1.AddressError('IPv4 integer must be in the range 0 to 2**32 - 1');
|
|
223
|
+
}
|
|
224
|
+
return Address4.fromHex(integer.toString(16).padStart(8, '0'));
|
|
127
225
|
}
|
|
128
226
|
/**
|
|
129
|
-
* Return an address from in-addr.arpa form
|
|
130
|
-
*
|
|
131
|
-
*
|
|
227
|
+
* Return an address from in-addr.arpa form: the four octets reversed, with
|
|
228
|
+
* or without the `.in-addr.arpa` suffix and root dot, in any case. Throws
|
|
229
|
+
* `AddressError` unless the reversed labels form a valid IPv4 address, so
|
|
230
|
+
* `fromArpa(x.reverseForm())` round-trips {@link reverseForm}.
|
|
132
231
|
* @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
|
|
133
232
|
* @returns {Adress4}
|
|
134
233
|
* @example
|
|
135
|
-
* var address = Address4.fromArpa(42.2.0.192.in-addr.arpa.)
|
|
234
|
+
* var address = Address4.fromArpa('42.2.0.192.in-addr.arpa.')
|
|
136
235
|
* address.correctForm(); // '192.0.2.42'
|
|
137
236
|
*/
|
|
138
237
|
static fromArpa(arpaFormAddress) {
|
|
139
|
-
// remove ending ".in-addr.arpa
|
|
140
|
-
|
|
238
|
+
// remove an ending ".in-addr.arpa", in any case and with or without the
|
|
239
|
+
// root dot, as Address6.fromArpa does for ".ip6.arpa"
|
|
240
|
+
const leader = arpaFormAddress.replace(/(\.in-addr\.arpa)?\.?$/i, '');
|
|
141
241
|
const address = leader.split('.').reverse().join('.');
|
|
142
242
|
return new Address4(address);
|
|
143
243
|
}
|
|
144
244
|
/**
|
|
145
245
|
* Converts an IPv4 address object to a hex string
|
|
146
|
-
* @memberof Address4
|
|
147
|
-
* @instance
|
|
148
246
|
* @returns {String}
|
|
149
247
|
*/
|
|
150
248
|
toHex() {
|
|
151
249
|
return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(':');
|
|
152
250
|
}
|
|
153
251
|
/**
|
|
154
|
-
* Converts an IPv4 address object to an array of bytes
|
|
155
|
-
*
|
|
156
|
-
*
|
|
252
|
+
* Converts an IPv4 address object to an array of bytes.
|
|
253
|
+
*
|
|
254
|
+
* To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`.
|
|
157
255
|
* @returns {Array}
|
|
158
256
|
*/
|
|
159
257
|
toArray() {
|
|
@@ -161,8 +259,6 @@ class Address4 {
|
|
|
161
259
|
}
|
|
162
260
|
/**
|
|
163
261
|
* Converts an IPv4 address object to an IPv6 address group
|
|
164
|
-
* @memberof Address4
|
|
165
|
-
* @instance
|
|
166
262
|
* @returns {String}
|
|
167
263
|
*/
|
|
168
264
|
toGroup6() {
|
|
@@ -175,8 +271,6 @@ class Address4 {
|
|
|
175
271
|
}
|
|
176
272
|
/**
|
|
177
273
|
* Returns the address as a `bigint`
|
|
178
|
-
* @memberof Address4
|
|
179
|
-
* @instance
|
|
180
274
|
* @returns {bigint}
|
|
181
275
|
*/
|
|
182
276
|
bigInt() {
|
|
@@ -184,8 +278,6 @@ class Address4 {
|
|
|
184
278
|
}
|
|
185
279
|
/**
|
|
186
280
|
* Helper function getting start address.
|
|
187
|
-
* @memberof Address4
|
|
188
|
-
* @instance
|
|
189
281
|
* @returns {bigint}
|
|
190
282
|
*/
|
|
191
283
|
_startAddress() {
|
|
@@ -194,8 +286,6 @@ class Address4 {
|
|
|
194
286
|
/**
|
|
195
287
|
* The first address in the range given by this address' subnet.
|
|
196
288
|
* Often referred to as the Network Address.
|
|
197
|
-
* @memberof Address4
|
|
198
|
-
* @instance
|
|
199
289
|
* @returns {Address4}
|
|
200
290
|
*/
|
|
201
291
|
startAddress() {
|
|
@@ -204,18 +294,41 @@ class Address4 {
|
|
|
204
294
|
/**
|
|
205
295
|
* The first host address in the range given by this address's subnet ie
|
|
206
296
|
* the first address after the Network Address
|
|
207
|
-
* @memberof Address4
|
|
208
|
-
* @instance
|
|
209
297
|
* @returns {Address4}
|
|
210
298
|
*/
|
|
211
299
|
startAddressExclusive() {
|
|
212
300
|
const adjust = BigInt('1');
|
|
213
301
|
return Address4.fromBigInt(this._startAddress() + adjust);
|
|
214
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* Returns the address `n` addresses after this one (or before, when `n` is
|
|
305
|
+
* negative), keeping this address's subnet mask. Throws `AddressError` when
|
|
306
|
+
* the result would fall outside the IPv4 address space or `n` is not an
|
|
307
|
+
* integer.
|
|
308
|
+
* @param {number | bigint} n
|
|
309
|
+
* @returns {Address4}
|
|
310
|
+
* @example
|
|
311
|
+
* new Address4('10.0.0.0/24').offset(1).correctForm(); // '10.0.0.1'
|
|
312
|
+
*/
|
|
313
|
+
offset(n) {
|
|
314
|
+
return Address4.fromBigInt(common.offsetBigInt(this.bigInt(), n, constants.BITS, 'IPv4')).withSubnetMask(this.subnetMask);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Returns the network that follows this address's network: the address after
|
|
318
|
+
* {@link endAddress}, with the same subnet mask. Throws `AddressError` when
|
|
319
|
+
* this network is the last one in the address space.
|
|
320
|
+
* @returns {Address4}
|
|
321
|
+
* @example
|
|
322
|
+
* new Address4('10.0.0.0/24').nextNetwork().networkForm(); // '10.0.1.0/24'
|
|
323
|
+
*/
|
|
324
|
+
nextNetwork() {
|
|
325
|
+
return Address4.fromBigInt(common.offsetBigInt(this._endAddress(), 1, constants.BITS, 'IPv4')).withSubnetMask(this.subnetMask);
|
|
326
|
+
}
|
|
327
|
+
withSubnetMask(subnetMask) {
|
|
328
|
+
return new Address4(`${this.correctForm()}/${subnetMask}`);
|
|
329
|
+
}
|
|
215
330
|
/**
|
|
216
331
|
* Helper function getting end address.
|
|
217
|
-
* @memberof Address4
|
|
218
|
-
* @instance
|
|
219
332
|
* @returns {bigint}
|
|
220
333
|
*/
|
|
221
334
|
_endAddress() {
|
|
@@ -224,8 +337,6 @@ class Address4 {
|
|
|
224
337
|
/**
|
|
225
338
|
* The last address in the range given by this address' subnet
|
|
226
339
|
* Often referred to as the Broadcast
|
|
227
|
-
* @memberof Address4
|
|
228
|
-
* @instance
|
|
229
340
|
* @returns {Address4}
|
|
230
341
|
*/
|
|
231
342
|
endAddress() {
|
|
@@ -234,8 +345,6 @@ class Address4 {
|
|
|
234
345
|
/**
|
|
235
346
|
* The last host address in the range given by this address's subnet ie
|
|
236
347
|
* the last address prior to the Broadcast Address
|
|
237
|
-
* @memberof Address4
|
|
238
|
-
* @instance
|
|
239
348
|
* @returns {Address4}
|
|
240
349
|
*/
|
|
241
350
|
endAddressExclusive() {
|
|
@@ -243,38 +352,64 @@ class Address4 {
|
|
|
243
352
|
return Address4.fromBigInt(this._endAddress() - adjust);
|
|
244
353
|
}
|
|
245
354
|
/**
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
* @
|
|
355
|
+
* The dotted-decimal form of the subnet mask, e.g. `255.255.240.0` for
|
|
356
|
+
* a `/20`. Returns an `Address4`; call `.correctForm()` for the string.
|
|
357
|
+
* @returns {Address4}
|
|
358
|
+
*/
|
|
359
|
+
subnetMaskAddress() {
|
|
360
|
+
return Address4.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants.BITS - this.subnetMask)}`));
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is
|
|
364
|
+
* the bitwise inverse of `subnetMaskAddress()`. Returns an `Address4`;
|
|
365
|
+
* call `.correctForm()` for the string.
|
|
366
|
+
* @returns {Address4}
|
|
367
|
+
*/
|
|
368
|
+
wildcardMask() {
|
|
369
|
+
return Address4.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants.BITS - this.subnetMask)}`));
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* The network address in CIDR string form, e.g. `192.168.1.0/24` for
|
|
373
|
+
* `192.168.1.5/24`. For an address with no explicit subnet the prefix is
|
|
374
|
+
* `/32`, e.g. `networkForm()` on `192.168.1.5` returns `192.168.1.5/32`.
|
|
375
|
+
* @returns {string}
|
|
376
|
+
*/
|
|
377
|
+
networkForm() {
|
|
378
|
+
return `${this.startAddress().correctForm()}/${this.subnetMask}`;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Converts a BigInt to a v4 address object. The value must be in the
|
|
382
|
+
* range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown.
|
|
249
383
|
* @param {bigint} bigInt - a BigInt to convert
|
|
250
384
|
* @returns {Address4}
|
|
251
385
|
*/
|
|
252
386
|
static fromBigInt(bigInt) {
|
|
253
|
-
|
|
387
|
+
if (bigInt < BigInt(0) || bigInt > BigInt(0xffffffff)) {
|
|
388
|
+
throw new address_error_1.AddressError('IPv4 BigInt must be in the range 0 to 2**32 - 1');
|
|
389
|
+
}
|
|
390
|
+
return Address4.fromHex(bigInt.toString(16).padStart(8, '0'));
|
|
254
391
|
}
|
|
255
392
|
/**
|
|
256
|
-
* Convert a byte array to an Address4 object
|
|
257
|
-
*
|
|
258
|
-
*
|
|
393
|
+
* Convert a byte array to an Address4 object. Throws `AddressError` unless
|
|
394
|
+
* given exactly 4 integers from 0 to 255. Signed bytes are rejected, so
|
|
395
|
+
* this differs from `Address6.fromByteArray`, which folds them; the two
|
|
396
|
+
* contracts converge on this stricter form in the next major version.
|
|
397
|
+
*
|
|
398
|
+
* To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`.
|
|
259
399
|
* @param {Array<number>} bytes - an array of 4 bytes (0-255)
|
|
260
400
|
* @returns {Address4}
|
|
261
401
|
*/
|
|
262
402
|
static fromByteArray(bytes) {
|
|
263
|
-
|
|
264
|
-
throw new address_error_1.AddressError('IPv4 addresses require exactly 4 bytes');
|
|
265
|
-
}
|
|
266
|
-
// Validate that all bytes are within valid range (0-255)
|
|
267
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
268
|
-
if (!Number.isInteger(bytes[i]) || bytes[i] < 0 || bytes[i] > 255) {
|
|
269
|
-
throw new address_error_1.AddressError('All bytes must be integers between 0 and 255');
|
|
270
|
-
}
|
|
271
|
-
}
|
|
403
|
+
common.assertByteArray(bytes, 4, 'IPv4', 0);
|
|
272
404
|
return this.fromUnsignedByteArray(bytes);
|
|
273
405
|
}
|
|
274
406
|
/**
|
|
275
|
-
* Convert an unsigned byte array to an Address4 object
|
|
276
|
-
*
|
|
277
|
-
*
|
|
407
|
+
* Convert an unsigned byte array to an Address4 object. Throws
|
|
408
|
+
* `AddressError` unless given exactly 4 bytes, and rejects values outside
|
|
409
|
+
* 0 to 255 when parsing the resulting address.
|
|
410
|
+
*
|
|
411
|
+
* To convert from a Node.js `Buffer`, spread it:
|
|
412
|
+
* `Address4.fromUnsignedByteArray([...buf])`.
|
|
278
413
|
* @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
|
|
279
414
|
* @returns {Address4}
|
|
280
415
|
*/
|
|
@@ -288,8 +423,6 @@ class Address4 {
|
|
|
288
423
|
/**
|
|
289
424
|
* Returns the first n bits of the address, defaulting to the
|
|
290
425
|
* subnet mask
|
|
291
|
-
* @memberof Address4
|
|
292
|
-
* @instance
|
|
293
426
|
* @returns {String}
|
|
294
427
|
*/
|
|
295
428
|
mask(mask) {
|
|
@@ -300,19 +433,16 @@ class Address4 {
|
|
|
300
433
|
}
|
|
301
434
|
/**
|
|
302
435
|
* Returns the bits in the given range as a base-2 string
|
|
303
|
-
* @memberof Address4
|
|
304
|
-
* @instance
|
|
305
436
|
* @returns {string}
|
|
306
437
|
*/
|
|
307
438
|
getBitsBase2(start, end) {
|
|
308
439
|
return this.binaryZeroPad().slice(start, end);
|
|
309
440
|
}
|
|
310
441
|
/**
|
|
311
|
-
* Return the reversed
|
|
312
|
-
*
|
|
442
|
+
* Return the reversed in-addr.arpa form of the address, e.g.
|
|
443
|
+
* `42.2.0.192.in-addr.arpa.` for `192.0.2.42`.
|
|
313
444
|
* @param {Object} options
|
|
314
445
|
* @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
|
|
315
|
-
* @instance
|
|
316
446
|
* @returns {String}
|
|
317
447
|
*/
|
|
318
448
|
reverseForm(options) {
|
|
@@ -327,29 +457,112 @@ class Address4 {
|
|
|
327
457
|
}
|
|
328
458
|
/**
|
|
329
459
|
* Returns true if the given address is a multicast address
|
|
330
|
-
* @memberof Address4
|
|
331
|
-
* @instance
|
|
332
460
|
* @returns {boolean}
|
|
333
461
|
*/
|
|
334
462
|
isMulticast() {
|
|
335
|
-
return this.
|
|
463
|
+
return this.isHostInSubnet(MULTICAST_V4);
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* 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`).
|
|
467
|
+
* @returns {boolean}
|
|
468
|
+
*/
|
|
469
|
+
isPrivate() {
|
|
470
|
+
return PRIVATE_V4.some((subnet) => this.isHostInSubnet(subnet));
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)).
|
|
474
|
+
* @returns {boolean}
|
|
475
|
+
*/
|
|
476
|
+
isLoopback() {
|
|
477
|
+
return this.isHostInSubnet(LOOPBACK_V4);
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* 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)).
|
|
481
|
+
* @returns {boolean}
|
|
482
|
+
*/
|
|
483
|
+
isLinkLocal() {
|
|
484
|
+
return this.isHostInSubnet(LINK_LOCAL_V4);
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Returns true if the address is the unspecified address `0.0.0.0`.
|
|
488
|
+
* @returns {boolean}
|
|
489
|
+
*/
|
|
490
|
+
isUnspecified() {
|
|
491
|
+
return this.isHostInSubnet(UNSPECIFIED_V4);
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)).
|
|
495
|
+
* @returns {boolean}
|
|
496
|
+
*/
|
|
497
|
+
isBroadcast() {
|
|
498
|
+
return this.isHostInSubnet(BROADCAST_V4);
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* 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)).
|
|
502
|
+
* @returns {boolean}
|
|
503
|
+
*/
|
|
504
|
+
isCGNAT() {
|
|
505
|
+
return this.isHostInSubnet(CGNAT_V4);
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Returns true if the address is in one of the documentation ranges
|
|
509
|
+
* `192.0.2.0/24`, `198.51.100.0/24`, or `203.0.113.0/24` ([RFC 5737](https://datatracker.ietf.org/doc/html/rfc5737)).
|
|
510
|
+
* @returns {boolean}
|
|
511
|
+
*/
|
|
512
|
+
isDocumentation() {
|
|
513
|
+
return DOCUMENTATION_V4.some((subnet) => this.isHostInSubnet(subnet));
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Returns true if the address is in the benchmarking range `198.18.0.0/15` ([RFC 2544](https://datatracker.ietf.org/doc/html/rfc2544)).
|
|
517
|
+
* @returns {boolean}
|
|
518
|
+
*/
|
|
519
|
+
isBenchmarking() {
|
|
520
|
+
return this.isHostInSubnet(BENCHMARKING_V4);
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Returns true if the address is in the reserved range `240.0.0.0/4` ([RFC 1112](https://datatracker.ietf.org/doc/html/rfc1112)),
|
|
524
|
+
* which includes the limited broadcast address.
|
|
525
|
+
* @returns {boolean}
|
|
526
|
+
*/
|
|
527
|
+
isReserved() {
|
|
528
|
+
return this.isHostInSubnet(RESERVED_V4);
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Returns true if the address is globally reachable: not multicast, and not
|
|
532
|
+
* in any block the [IANA IPv4 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/)
|
|
533
|
+
* marks as not globally reachable. That covers everything the individual
|
|
534
|
+
* classifiers name (private, loopback, link-local, CGNAT, unspecified,
|
|
535
|
+
* broadcast, documentation, benchmarking, reserved) and the blocks they do
|
|
536
|
+
* not, such as `0.0.0.0/8` and the IETF protocol assignments in
|
|
537
|
+
* `192.0.0.0/24`. This is the single predicate to use where a request must
|
|
538
|
+
* not reach an internal or special-purpose destination; see SECURITY.md.
|
|
539
|
+
* @returns {boolean}
|
|
540
|
+
*/
|
|
541
|
+
isGlobal() {
|
|
542
|
+
return !this.isMulticast() && common.isGloballyReachable.call(this, SPECIAL_PURPOSE_V4);
|
|
336
543
|
}
|
|
337
544
|
/**
|
|
338
545
|
* Returns a zero-padded base-2 string representation of the address
|
|
339
|
-
* @memberof Address4
|
|
340
|
-
* @instance
|
|
341
546
|
* @returns {string}
|
|
342
547
|
*/
|
|
343
548
|
binaryZeroPad() {
|
|
344
|
-
|
|
549
|
+
if (this._binaryZeroPad === undefined) {
|
|
550
|
+
this._binaryZeroPad = this.bigInt().toString(2).padStart(constants.BITS, '0');
|
|
551
|
+
}
|
|
552
|
+
return this._binaryZeroPad;
|
|
345
553
|
}
|
|
346
554
|
/**
|
|
347
|
-
* Groups an IPv4 address for inclusion at the end of an IPv6 address
|
|
555
|
+
* Groups an IPv4 address for inclusion at the end of an IPv6 address.
|
|
556
|
+
*
|
|
557
|
+
* Returns an HTML fragment: each half of the address is wrapped in a
|
|
558
|
+
* `<span>` carrying the group classes an address-inspector UI hovers on.
|
|
559
|
+
* The address content is HTML-escaped; anything you concatenate around it
|
|
560
|
+
* is your responsibility.
|
|
348
561
|
* @returns {String}
|
|
349
562
|
*/
|
|
350
563
|
groupForV6() {
|
|
351
564
|
const segments = this.parsedAddress;
|
|
352
|
-
return this.
|
|
565
|
+
return this.correctForm().replace(constants.RE_ADDRESS, `<span class="hover-group group-v4 group-6">${segments
|
|
353
566
|
.slice(0, 2)
|
|
354
567
|
.join('.')}</span>.<span class="hover-group group-v4 group-7">${segments
|
|
355
568
|
.slice(2, 4)
|
|
@@ -357,4 +570,26 @@ class Address4 {
|
|
|
357
570
|
}
|
|
358
571
|
}
|
|
359
572
|
exports.Address4 = Address4;
|
|
573
|
+
const MULTICAST_V4 = new Address4('224.0.0.0/4');
|
|
574
|
+
const PRIVATE_V4 = [
|
|
575
|
+
new Address4('10.0.0.0/8'),
|
|
576
|
+
new Address4('172.16.0.0/12'),
|
|
577
|
+
new Address4('192.168.0.0/16'),
|
|
578
|
+
];
|
|
579
|
+
const LOOPBACK_V4 = new Address4('127.0.0.0/8');
|
|
580
|
+
const LINK_LOCAL_V4 = new Address4('169.254.0.0/16');
|
|
581
|
+
const UNSPECIFIED_V4 = new Address4('0.0.0.0/32');
|
|
582
|
+
const BROADCAST_V4 = new Address4('255.255.255.255/32');
|
|
583
|
+
const CGNAT_V4 = new Address4('100.64.0.0/10');
|
|
584
|
+
const DOCUMENTATION_V4 = [
|
|
585
|
+
new Address4('192.0.2.0/24'),
|
|
586
|
+
new Address4('198.51.100.0/24'),
|
|
587
|
+
new Address4('203.0.113.0/24'),
|
|
588
|
+
];
|
|
589
|
+
const BENCHMARKING_V4 = new Address4('198.18.0.0/15');
|
|
590
|
+
const RESERVED_V4 = new Address4('240.0.0.0/4');
|
|
591
|
+
const SPECIAL_PURPOSE_V4 = constants.SPECIAL_PURPOSE.map(([cidr, , reachable]) => ({
|
|
592
|
+
subnet: new Address4(cidr),
|
|
593
|
+
reachable,
|
|
594
|
+
}));
|
|
360
595
|
//# sourceMappingURL=ipv4.js.map
|