| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -179,6 +179,38 @@ added: v22.13.0 | |||
| 179 | 179 | * `value` {any} Any JS value | |
| 180 | 180 | * Returns `true` if the `value` is a `net.BlockList`. | |
| 181 | 181 | ||
| 182 | + ### `blockList.fromJSON(value)` | ||
| 183 | + | ||
| 184 | + > Stability: 1 - Experimental | ||
| 185 | + | ||
| 186 | + <!-- YAML | ||
| 187 | + added: REPLACEME | ||
| 188 | + --> | ||
| 189 | + | ||
| 190 | + ```js | ||
| 191 | + const blockList = new net.BlockList(); | ||
| 192 | + const data = [ | ||
| 193 | + 'Subnet: IPv4 192.168.1.0/24', | ||
| 194 | + 'Address: IPv4 10.0.0.5', | ||
| 195 | + 'Range: IPv4 192.168.2.1-192.168.2.10', | ||
| 196 | + 'Range: IPv4 10.0.0.1-10.0.0.10', | ||
| 197 | + ]; | ||
| 198 | + blockList.fromJSON(data); | ||
| 199 | + blockList.fromJSON(JSON.stringify(data)); | ||
| 200 | + ``` | ||
| 201 | + | ||
| 202 | + * `value` Blocklist.rules | ||
| 203 | + | ||
| 204 | + ### `blockList.toJSON()` | ||
| 205 | + | ||
| 206 | + > Stability: 1 - Experimental | ||
| 207 | + | ||
| 208 | + <!-- YAML | ||
| 209 | + added: REPLACEME | ||
| 210 | + --> | ||
| 211 | + | ||
| 212 | + * Returns Blocklist.rules | ||
| 213 | + | ||
| 182 | 214 | ## Class: `net.SocketAddress` | |
| 183 | 215 | ||
| 184 | 216 | <!-- YAML | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,7 +1,10 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | 2 | ||
| 3 | 3 | const { | |
| 4 | + ArrayIsArray, | ||
| 4 | 5 | Boolean, | |
| 6 | + JSONParse, | ||
| 7 | + NumberParseInt, | ||
| 5 | 8 | ObjectSetPrototypeOf, | |
| 6 | 9 | Symbol, | |
| 7 | 10 | } = primordials; | |
@@ -32,6 +35,7 @@ const { owner_symbol } = internalBinding('symbols'); | |||
| 32 | 35 | ||
| 33 | 36 | const { | |
| 34 | 37 | ERR_INVALID_ARG_VALUE, | |
| 38 | + ERR_INVALID_ARG_TYPE, | ||
| 35 | 39 | } = require('internal/errors').codes; | |
| 36 | 40 | ||
| 37 | 41 | const { validateInt32, validateString } = require('internal/validators'); | |
@@ -139,10 +143,130 @@ class BlockList { | |||
| 139 | 143 | return Boolean(this[kHandle].check(address[kSocketAddressHandle])); | |
| 140 | 144 | } | |
| 141 | 145 | ||
| 146 | + /* | ||
| 147 | + * @param {string[]} data | ||
| 148 | + * @example | ||
| 149 | + * const data = [ | ||
| 150 | + * // IPv4 examples | ||
| 151 | + * 'Subnet: IPv4 192.168.1.0/24', | ||
| 152 | + * 'Address: IPv4 10.0.0.5', | ||
| 153 | + * 'Range: IPv4 192.168.2.1-192.168.2.10', | ||
| 154 | + * 'Range: IPv4 10.0.0.1-10.0.0.10', | ||
| 155 | + * | ||
| 156 | + * // IPv6 examples | ||
| 157 | + * 'Subnet: IPv6 2001:0db8:85a3:0000:0000:8a2e:0370:7334/64', | ||
| 158 | + * 'Address: IPv6 2001:0db8:85a3:0000:0000:8a2e:0370:7334', | ||
| 159 | + * 'Range: IPv6 2001:0db8:85a3:0000:0000:8a2e:0370:7334-2001:0db8:85a3:0000:0000:8a2e:0370:7335', | ||
| 160 | + * 'Subnet: IPv6 2001:db8:1234::/48', | ||
| 161 | + * 'Address: IPv6 2001:db8:1234::1', | ||
| 162 | + * 'Range: IPv6 2001:db8:1234::1-2001:db8:1234::10' | ||
| 163 | + * ]; | ||
| 164 | + */ | ||
| 165 | + #parseIPInfo(data) { | ||
| 166 | + for (const item of data) { | ||
| 167 | + if (item.includes('IPv4')) { | ||
| 168 | + const subnetMatch = item.match( | ||
| 169 | + /Subnet: IPv4 (\d{1,3}(?:\.\d{1,3}){3})\/(\d{1,2})/, | ||
| 170 | + ); | ||
| 171 | + if (subnetMatch) { | ||
| 172 | + const { 1: network, 2: prefix } = subnetMatch; | ||
| 173 | + this.addSubnet(network, NumberParseInt(prefix)); | ||
| 174 | + continue; | ||
| 175 | + } | ||
| 176 | + const addressMatch = item.match(/Address: IPv4 (\d{1,3}(?:\.\d{1,3}){3})/); | ||
| 177 | + if (addressMatch) { | ||
| 178 | + const { 1: address } = addressMatch; | ||
| 179 | + this.addAddress(address); | ||
| 180 | + continue; | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + const rangeMatch = item.match( | ||
| 184 | + /Range: IPv4 (\d{1,3}(?:\.\d{1,3}){3})-(\d{1,3}(?:\.\d{1,3}){3})/, | ||
| 185 | + ); | ||
| 186 | + if (rangeMatch) { | ||
| 187 | + const { 1: start, 2: end } = rangeMatch; | ||
| 188 | + this.addRange(start, end); | ||
| 189 | + continue; | ||
| 190 | + } | ||
| 191 | + } | ||
| 192 | + // IPv6 parsing with support for compressed addresses | ||
| 193 | + if (item.includes('IPv6')) { | ||
| 194 | + // IPv6 subnet pattern: supports both full and compressed formats | ||
| 195 | + // Examples: | ||
| 196 | + // - 2001:0db8:85a3:0000:0000:8a2e:0370:7334/64 (full) | ||
| 197 | + // - 2001:db8:85a3::8a2e:370:7334/64 (compressed) | ||
| 198 | + // - 2001:db8:85a3::192.0.2.128/64 (mixed) | ||
| 199 | + const ipv6SubnetMatch = item.match( | ||
| 200 | + /Subnet: IPv6 ([0-9a-fA-F:]{1,39})\/([0-9]{1,3})/i, | ||
| 201 | + ); | ||
| 202 | + if (ipv6SubnetMatch) { | ||
| 203 | + const { 1: network, 2: prefix } = ipv6SubnetMatch; | ||
| 204 | + this.addSubnet(network, NumberParseInt(prefix), 'ipv6'); | ||
| 205 | + continue; | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + // IPv6 address pattern: supports both full and compressed formats | ||
| 209 | + // Examples: | ||
| 210 | + // - 2001:0db8:85a3:0000:0000:8a2e:0370:7334 (full) | ||
| 211 | + // - 2001:db8:85a3::8a2e:370:7334 (compressed) | ||
| 212 | + // - 2001:db8:85a3::192.0.2.128 (mixed) | ||
| 213 | + const ipv6AddressMatch = item.match(/Address: IPv6 ([0-9a-fA-F:]{1,39})/i); | ||
| 214 | + if (ipv6AddressMatch) { | ||
| 215 | + const { 1: address } = ipv6AddressMatch; | ||
| 216 | + this.addAddress(address, 'ipv6'); | ||
| 217 | + continue; | ||
| 218 | + } | ||
| 219 | + | ||
| 220 | + // IPv6 range pattern: supports both full and compressed formats | ||
| 221 | + // Examples: | ||
| 222 | + // - 2001:0db8:85a3:0000:0000:8a2e:0370:7334-2001:0db8:85a3:0000:0000:8a2e:0370:7335 (full) | ||
| 223 | + // - 2001:db8:85a3::8a2e:370:7334-2001:db8:85a3::8a2e:370:7335 (compressed) | ||
| 224 | + // - 2001:db8:85a3::192.0.2.128-2001:db8:85a3::192.0.2.129 (mixed) | ||
| 225 | + const ipv6RangeMatch = item.match(/Range: IPv6 ([0-9a-fA-F:]{1,39})-([0-9a-fA-F:]{1,39})/i); | ||
| 226 | + if (ipv6RangeMatch) { | ||
| 227 | + const { 1: start, 2: end } = ipv6RangeMatch; | ||
| 228 | + this.addRange(start, end, 'ipv6'); | ||
| 229 | + continue; | ||
| 230 | + } | ||
| 231 | + } | ||
| 232 | + } | ||
| 233 | + } | ||
| 234 | + | ||
| 235 | + | ||
| 236 | + toJSON() { | ||
| 237 | + return this.rules; | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + fromJSON(data) { | ||
| 241 | + // The data argument must be a string, or an array of strings that | ||
| 242 | + // is JSON parseable. | ||
| 243 | + if (ArrayIsArray(data)) { | ||
| 244 | + for (const n of data) { | ||
| 245 | + if (typeof n !== 'string') { | ||
| 246 | + throw new ERR_INVALID_ARG_TYPE('data', ['string', 'string[]'], data); | ||
| 247 | + } | ||
| 248 | + } | ||
| 249 | + } else if (typeof data !== 'string') { | ||
| 250 | + throw new ERR_INVALID_ARG_TYPE('data', ['string', 'string[]'], data); | ||
| 251 | + } else { | ||
| 252 | + data = JSONParse(data); | ||
| 253 | + if (!ArrayIsArray(data)) { | ||
| 254 | + throw new ERR_INVALID_ARG_TYPE('data', ['string', 'string[]'], data); | ||
| 255 | + } | ||
| 256 | + for (const n of data) { | ||
| 257 | + if (typeof n !== 'string') { | ||
| 258 | + throw new ERR_INVALID_ARG_TYPE('data', ['string', 'string[]'], data); | ||
| 259 | + } | ||
| 260 | + } | ||
| 261 | + } | ||
| 262 | + | ||
| 263 | + this.#parseIPInfo(data); | ||
| 264 | + } | ||
| 265 | + | ||
| 266 | + | ||
| 142 | 267 | get rules() { | |
| 143 | 268 | return this[kHandle].getRules(); | |
| 144 | 269 | } | |
| 145 | - | ||
| 146 | 270 | [kClone]() { | |
| 147 | 271 | const handle = this[kHandle]; | |
| 148 | 272 | return { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -287,3 +287,75 @@ const util = require('util'); | |||
| 287 | 287 | assert(BlockList.isBlockList(new BlockList())); | |
| 288 | 288 | assert(!BlockList.isBlockList({})); | |
| 289 | 289 | } | |
| 290 | + | ||
| 291 | + // Test exporting and importing the rule list to/from JSON | ||
| 292 | + { | ||
| 293 | + const ruleList = [ | ||
| 294 | + 'Address: IPv4 10.0.0.5', | ||
| 295 | + 'Address: IPv6 ::', | ||
| 296 | + 'Subnet: IPv4 192.168.1.0/24', | ||
| 297 | + 'Subnet: IPv6 8592:757c:efae:4e45::/64', | ||
| 298 | + ]; | ||
| 299 | + | ||
| 300 | + const test2 = new BlockList(); | ||
| 301 | + const test3 = new BlockList(); | ||
| 302 | + const test4 = new BlockList(); | ||
| 303 | + const test5 = new BlockList(); | ||
| 304 | + | ||
| 305 | + const bl = new BlockList(); | ||
| 306 | + bl.addAddress('10.0.0.5'); | ||
| 307 | + bl.addAddress('::', 'ipv6'); | ||
| 308 | + bl.addSubnet('192.168.1.0', 24); | ||
| 309 | + bl.addSubnet('8592:757c:efae:4e45::', 64, 'ipv6'); | ||
| 310 | + | ||
| 311 | + // Test invalid inputs (input to fromJSON must be an array of | ||
| 312 | + // string rules or a serialized json string of an array of | ||
| 313 | + // string rules. | ||
| 314 | + [ | ||
| 315 | + 1, null, Symbol(), [1, 2, 3], '123', [Symbol()], new Map(), | ||
| 316 | + ].forEach((i) => { | ||
| 317 | + assert.throws(() => test2.fromJSON(i), { | ||
| 318 | + code: 'ERR_INVALID_ARG_TYPE', | ||
| 319 | + }); | ||
| 320 | + }); | ||
| 321 | + | ||
| 322 | + // Invalid rules are ignored. | ||
| 323 | + test2.fromJSON(['1', '2', '3']); | ||
| 324 | + assert.deepStrictEqual(test2.rules, []); | ||
| 325 | + | ||
| 326 | + // Direct output from toJSON method works | ||
| 327 | + test2.fromJSON(bl.toJSON()); | ||
| 328 | + assert.deepStrictEqual(test2.rules.sort(), ruleList); | ||
| 329 | + | ||
| 330 | + // JSON stringified output works | ||
| 331 | + test3.fromJSON(JSON.stringify(bl)); | ||
| 332 | + assert.deepStrictEqual(test3.rules.sort(), ruleList); | ||
| 333 | + | ||
| 334 | + // A raw array works | ||
| 335 | + test4.fromJSON(ruleList); | ||
| 336 | + assert.deepStrictEqual(test4.rules.sort(), ruleList); | ||
| 337 | + | ||
| 338 | + // Individual rules work | ||
| 339 | + ruleList.forEach((item) => { | ||
| 340 | + test5.fromJSON([item]); | ||
| 341 | + }); | ||
| 342 | + assert.deepStrictEqual(test5.rules.sort(), ruleList); | ||
| 343 | + | ||
| 344 | + // Each of the created blocklists should handle the checks identically. | ||
| 345 | + [ | ||
| 346 | + ['10.0.0.5', 'ipv4', true], | ||
| 347 | + ['10.0.0.6', 'ipv4', false], | ||
| 348 | + ['::', 'ipv6', true], | ||
| 349 | + ['::1', 'ipv6', false], | ||
| 350 | + ['192.168.1.0', 'ipv4', true], | ||
| 351 | + ['193.168.1.0', 'ipv4', false], | ||
| 352 | + ['8592:757c:efae:4e45::', 'ipv6', true], | ||
| 353 | + ['1111:1111:1111:1111::', 'ipv6', false], | ||
| 354 | + ].forEach((i) => { | ||
| 355 | + assert.strictEqual(bl.check(i[0], i[1]), i[2]); | ||
| 356 | + assert.strictEqual(test2.check(i[0], i[1]), i[2]); | ||
| 357 | + assert.strictEqual(test3.check(i[0], i[1]), i[2]); | ||
| 358 | + assert.strictEqual(test4.check(i[0], i[1]), i[2]); | ||
| 359 | + assert.strictEqual(test5.check(i[0], i[1]), i[2]); | ||
| 360 | + }); | ||
| 361 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3,7 +3,6 @@ | |||
| 3 | 3 | const common = require('../common'); | |
| 4 | 4 | const net = require('net'); | |
| 5 | 5 | const assert = require('assert'); | |
| 6 | - | ||
| 7 | 6 | const blockList = new net.BlockList(); | |
| 8 | 7 | blockList.addAddress('127.0.0.1'); | |
| 9 | 8 | blockList.addAddress('127.0.0.2'); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments