mybase 1.1.29 → 1.1.30
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/package.json +9 -9
- package/ts/funcs/isLANIp.js +12 -12
- package/ts/funcs/isLANIp.ts +15 -16
- package/ts/funcs/isLoopbackIP.js +14 -12
- package/ts/funcs/isLoopbackIP.ts +12 -12
- package/ts/index.test.ts +1 -1
- package/ts/models/IPAddress.js +93 -2
- package/ts/models/IPAddress.test.ts +134 -15
- package/ts/models/IPAddress.ts +98 -3
- package/tsconfig.json +2 -1
- package/types/ip6addr.d.ts +46 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mybase",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.30",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "mybase.js",
|
|
6
6
|
"scripts": {
|
|
@@ -10,25 +10,25 @@
|
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@7c/validurl": "0.0.3",
|
|
13
|
+
"@types/debug": "^4.1.12",
|
|
14
|
+
"@types/ip6addr": "^0.2.6",
|
|
15
|
+
"@types/mysql": "^2.15.25",
|
|
16
|
+
"@types/node": "^20.11.5",
|
|
17
|
+
"@types/request": "^2.48.12",
|
|
18
|
+
"@types/validator": "^13.11.8",
|
|
13
19
|
"aes-js": "^3.1.2",
|
|
14
20
|
"chalk": "^3.0.0",
|
|
15
21
|
"debug": "^4.3.4",
|
|
16
22
|
"ip-range-check": "^0.2.0",
|
|
17
23
|
"ip6": "=0.2.7",
|
|
18
|
-
"ip6addr": "
|
|
24
|
+
"ip6addr": "github:7c/node-ip6addr#db6d558af1f314bcb0a733fd61611fa85e1a3eff",
|
|
19
25
|
"js-sha512": "^0.8.0",
|
|
20
26
|
"mysql": "^2.18.1",
|
|
21
27
|
"mysql2": "^3.9.1",
|
|
22
28
|
"node-vault": "^0.10.2",
|
|
23
29
|
"psl": "^1.9.0",
|
|
24
30
|
"punycode": "^2.1.1",
|
|
25
|
-
"validator": "^13.7.0"
|
|
26
|
-
"@types/debug": "^4.1.12",
|
|
27
|
-
"@types/ip6addr": "^0.2.6",
|
|
28
|
-
"@types/mysql": "^2.15.25",
|
|
29
|
-
"@types/node": "^20.11.5",
|
|
30
|
-
"@types/validator": "^13.11.8",
|
|
31
|
-
"@types/request": "^2.48.12"
|
|
31
|
+
"validator": "^13.7.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@jest/globals": "^29.7.0",
|
package/ts/funcs/isLANIp.js
CHANGED
|
@@ -3,24 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isLANIp = void 0;
|
|
6
|
+
exports.isLANIp = exports.private_network_cidrs = void 0;
|
|
7
7
|
const ip6addr_1 = __importDefault(require("ip6addr"));
|
|
8
8
|
const net_1 = __importDefault(require("net"));
|
|
9
|
-
|
|
9
|
+
exports.private_network_cidrs = [
|
|
10
|
+
ip6addr_1.default.createCIDR('10.0.0.0/8'),
|
|
10
11
|
ip6addr_1.default.createCIDR('172.16.0.0/12'),
|
|
11
12
|
ip6addr_1.default.createCIDR('192.168.0.0/16'),
|
|
12
13
|
ip6addr_1.default.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
|
|
13
|
-
,
|
|
14
14
|
ip6addr_1.default.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
|
|
15
15
|
];
|
|
16
|
-
function normalizeIp(ip) {
|
|
17
|
-
// also support ipv6
|
|
18
|
-
if (net_1.default.isIP(ip) === 0)
|
|
19
|
-
return '';
|
|
20
|
-
if (net_1.default.isIPv6(ip))
|
|
21
|
-
return ip.toLowerCase().replace(/^::ffff:/, '');
|
|
22
|
-
return ip;
|
|
23
|
-
}
|
|
24
16
|
function isLANIp(ip) {
|
|
25
17
|
ip = normalizeIp(ip);
|
|
26
18
|
if (net_1.default.isIP(ip) === 0)
|
|
@@ -28,7 +20,7 @@ function isLANIp(ip) {
|
|
|
28
20
|
try {
|
|
29
21
|
// speed optimized
|
|
30
22
|
let ipVersion = net_1.default.isIPv4(ip) ? 'ipv4' : 'ipv6';
|
|
31
|
-
for (let cidr of private_network_cidrs) {
|
|
23
|
+
for (let cidr of exports.private_network_cidrs) {
|
|
32
24
|
if (!cidr)
|
|
33
25
|
continue;
|
|
34
26
|
let first = cidr.first();
|
|
@@ -44,4 +36,12 @@ function isLANIp(ip) {
|
|
|
44
36
|
return false;
|
|
45
37
|
}
|
|
46
38
|
exports.isLANIp = isLANIp;
|
|
39
|
+
function normalizeIp(ip) {
|
|
40
|
+
// also support ipv6
|
|
41
|
+
if (net_1.default.isIP(ip) === 0)
|
|
42
|
+
return '';
|
|
43
|
+
if (net_1.default.isIPv6(ip))
|
|
44
|
+
return ip.toLowerCase().replace(/^::ffff:/, '');
|
|
45
|
+
return ip;
|
|
46
|
+
}
|
|
47
47
|
//# sourceMappingURL=isLANIp.js.map
|
package/ts/funcs/isLANIp.ts
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
import ip6addr from 'ip6addr'
|
|
2
2
|
import net from 'net'
|
|
3
3
|
|
|
4
|
-
const private_network_cidrs = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
function normalizeIp(ip:string):string {
|
|
13
|
-
// also support ipv6
|
|
14
|
-
if (net.isIP(ip) === 0) return ''
|
|
15
|
-
if (net.isIPv6(ip)) return ip.toLowerCase().replace(/^::ffff:/, '')
|
|
16
|
-
return ip
|
|
17
|
-
}
|
|
18
|
-
|
|
4
|
+
export const private_network_cidrs = [
|
|
5
|
+
ip6addr.createCIDR('10.0.0.0/8'),
|
|
6
|
+
ip6addr.createCIDR('172.16.0.0/12'),
|
|
7
|
+
ip6addr.createCIDR('192.168.0.0/16'),
|
|
8
|
+
ip6addr.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
|
|
9
|
+
ip6addr.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
|
|
10
|
+
]
|
|
19
11
|
|
|
20
12
|
export function isLANIp(ip:string) : boolean {
|
|
21
13
|
ip=normalizeIp(ip)
|
|
22
|
-
if (net.isIP(ip)
|
|
14
|
+
if (net.isIP(ip)===0) return false
|
|
23
15
|
try {
|
|
24
16
|
// speed optimized
|
|
25
17
|
let ipVersion = net.isIPv4(ip) ? 'ipv4' : 'ipv6'
|
|
@@ -36,3 +28,10 @@ export function isLANIp(ip:string) : boolean {
|
|
|
36
28
|
}
|
|
37
29
|
return false
|
|
38
30
|
}
|
|
31
|
+
|
|
32
|
+
function normalizeIp(ip:string):string {
|
|
33
|
+
// also support ipv6
|
|
34
|
+
if (net.isIP(ip) === 0) return ''
|
|
35
|
+
if (net.isIPv6(ip)) return ip.toLowerCase().replace(/^::ffff:/, '')
|
|
36
|
+
return ip
|
|
37
|
+
}
|
package/ts/funcs/isLoopbackIP.js
CHANGED
|
@@ -3,19 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isLoopbackIP = void 0;
|
|
6
|
+
exports.isLoopbackIP = exports.local_network_cidrs = void 0;
|
|
7
7
|
const ip6addr_1 = __importDefault(require("ip6addr"));
|
|
8
8
|
const net_1 = __importDefault(require("net"));
|
|
9
|
-
|
|
10
|
-
ip6addr_1.default.createCIDR('
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (net_1.default.isIP(ip) === 0)
|
|
14
|
-
return '';
|
|
15
|
-
if (net_1.default.isIPv6(ip))
|
|
16
|
-
return ip.toLowerCase().replace(/^::ffff:/, '');
|
|
17
|
-
return ip;
|
|
18
|
-
}
|
|
9
|
+
exports.local_network_cidrs = [
|
|
10
|
+
ip6addr_1.default.createCIDR('127.0.0.0/8'),
|
|
11
|
+
ip6addr_1.default.createCIDR('::1/128')
|
|
12
|
+
];
|
|
19
13
|
function isLoopbackIP(ip) {
|
|
20
14
|
ip = normalizeIp(ip);
|
|
21
15
|
if (net_1.default.isIP(ip) === 0)
|
|
@@ -23,7 +17,7 @@ function isLoopbackIP(ip) {
|
|
|
23
17
|
try {
|
|
24
18
|
// speed optimized
|
|
25
19
|
let ipVersion = net_1.default.isIPv4(ip) ? 'ipv4' : 'ipv6';
|
|
26
|
-
for (let cidr of local_network_cidrs) {
|
|
20
|
+
for (let cidr of exports.local_network_cidrs) {
|
|
27
21
|
let first = cidr.first();
|
|
28
22
|
if (first.kind() !== ipVersion)
|
|
29
23
|
continue;
|
|
@@ -37,4 +31,12 @@ function isLoopbackIP(ip) {
|
|
|
37
31
|
return false;
|
|
38
32
|
}
|
|
39
33
|
exports.isLoopbackIP = isLoopbackIP;
|
|
34
|
+
function normalizeIp(ip) {
|
|
35
|
+
// also support ipv6
|
|
36
|
+
if (net_1.default.isIP(ip) === 0)
|
|
37
|
+
return '';
|
|
38
|
+
if (net_1.default.isIPv6(ip))
|
|
39
|
+
return ip.toLowerCase().replace(/^::ffff:/, '');
|
|
40
|
+
return ip;
|
|
41
|
+
}
|
|
40
42
|
//# sourceMappingURL=isLoopbackIP.js.map
|
package/ts/funcs/isLoopbackIP.ts
CHANGED
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import ip6addr from 'ip6addr'
|
|
2
2
|
import net from 'net'
|
|
3
3
|
|
|
4
|
-
const local_network_cidrs = [
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
function normalizeIp(ip:string):string {
|
|
9
|
-
// also support ipv6
|
|
10
|
-
if (net.isIP(ip) === 0) return ''
|
|
11
|
-
if (net.isIPv6(ip)) return ip.toLowerCase().replace(/^::ffff:/, '')
|
|
12
|
-
return ip
|
|
13
|
-
}
|
|
14
|
-
|
|
4
|
+
export const local_network_cidrs = [
|
|
5
|
+
ip6addr.createCIDR('127.0.0.0/8'),
|
|
6
|
+
ip6addr.createCIDR('::1/128')
|
|
7
|
+
]
|
|
15
8
|
|
|
16
9
|
export function isLoopbackIP(ip:string) : boolean {
|
|
17
10
|
ip=normalizeIp(ip)
|
|
18
|
-
if (net.isIP(ip)
|
|
11
|
+
if (net.isIP(ip)===0) return false
|
|
19
12
|
try {
|
|
20
13
|
// speed optimized
|
|
21
14
|
let ipVersion = net.isIPv4(ip) ? 'ipv4' : 'ipv6'
|
|
@@ -30,3 +23,10 @@ export function isLoopbackIP(ip:string) : boolean {
|
|
|
30
23
|
}
|
|
31
24
|
return false
|
|
32
25
|
}
|
|
26
|
+
|
|
27
|
+
function normalizeIp(ip:string):string {
|
|
28
|
+
// also support ipv6
|
|
29
|
+
if (net.isIP(ip) === 0) return ''
|
|
30
|
+
if (net.isIPv6(ip)) return ip.toLowerCase().replace(/^::ffff:/, '')
|
|
31
|
+
return ip
|
|
32
|
+
}
|
package/ts/index.test.ts
CHANGED
package/ts/models/IPAddress.js
CHANGED
|
@@ -4,9 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.IPAddress = void 0;
|
|
7
|
+
const debug_1 = __importDefault(require("debug"));
|
|
7
8
|
const __1 = require("./../");
|
|
8
9
|
const ip6addr_1 = __importDefault(require("ip6addr"));
|
|
10
|
+
const net_1 = __importDefault(require("net"));
|
|
9
11
|
const ip6 = require('ip6'); // "url": "https://github.com/elgs/ip6"
|
|
12
|
+
const dbg = (0, debug_1.default)('_IPAddress');
|
|
13
|
+
dbg.enabled = true;
|
|
10
14
|
// need version "ip6": "0.2.7",!!
|
|
11
15
|
class IPAddress {
|
|
12
16
|
constructor(ip) {
|
|
@@ -51,10 +55,33 @@ class IPAddress {
|
|
|
51
55
|
return new IPAddress('0.0.0.0');
|
|
52
56
|
}
|
|
53
57
|
isLoopbackIP() {
|
|
54
|
-
return
|
|
58
|
+
return this.partOfCIDR(IPAddress.loopback_cidrs);
|
|
55
59
|
}
|
|
56
60
|
isLANIP() {
|
|
57
|
-
return
|
|
61
|
+
return this.partOfCIDR(IPAddress.lan_cidrs);
|
|
62
|
+
}
|
|
63
|
+
isLocalIP() {
|
|
64
|
+
return this.partOfCIDR(IPAddress.local_cidrs);
|
|
65
|
+
}
|
|
66
|
+
partOfCIDR(cidr_networks) {
|
|
67
|
+
const ipNormalized = this.toString();
|
|
68
|
+
let ipVersion = net_1.default.isIPv4(ipNormalized) ? 'ipv4' : 'ipv6';
|
|
69
|
+
for (let cidr of cidr_networks) {
|
|
70
|
+
if (!cidr)
|
|
71
|
+
continue;
|
|
72
|
+
let first = cidr.first();
|
|
73
|
+
if (first.kind() !== ipVersion)
|
|
74
|
+
continue;
|
|
75
|
+
if (cidr.contains(ipNormalized))
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
static partOfCIDR(_ip, cidr_networks) {
|
|
81
|
+
const ip = IPAddress.try(_ip);
|
|
82
|
+
if (ip === undefined)
|
|
83
|
+
return false;
|
|
84
|
+
return ip.partOfCIDR(cidr_networks);
|
|
58
85
|
}
|
|
59
86
|
isPublicIP() {
|
|
60
87
|
return this.toString() !== '0.0.0.0' && !this.isLoopbackIP() && !this.isLANIP();
|
|
@@ -82,6 +109,50 @@ class IPAddress {
|
|
|
82
109
|
static randomIP6() {
|
|
83
110
|
return new IPAddress((0, __1.randomIP6)());
|
|
84
111
|
}
|
|
112
|
+
static randomCIDRIp(cidr) {
|
|
113
|
+
if (cidr === 'loopback')
|
|
114
|
+
cidr = IPAddress.loopback_cidrs;
|
|
115
|
+
if (cidr === 'loopback4')
|
|
116
|
+
cidr = IPAddress.loopback_cidrs4;
|
|
117
|
+
if (cidr === 'loopback6')
|
|
118
|
+
cidr = IPAddress.loopback_cidrs6;
|
|
119
|
+
if (cidr === 'lan')
|
|
120
|
+
cidr = IPAddress.lan_cidrs;
|
|
121
|
+
if (cidr === 'lan4')
|
|
122
|
+
cidr = IPAddress.lan_cidrs4;
|
|
123
|
+
if (cidr === 'lan6')
|
|
124
|
+
cidr = IPAddress.lan_cidrs6;
|
|
125
|
+
if (cidr === 'local')
|
|
126
|
+
cidr = IPAddress.local_cidrs;
|
|
127
|
+
if (cidr === 'local4')
|
|
128
|
+
cidr = IPAddress.local_cidrs4;
|
|
129
|
+
if (cidr === 'local6')
|
|
130
|
+
cidr = IPAddress.local_cidrs6;
|
|
131
|
+
// dbg('randomCIDRIp', cidr)
|
|
132
|
+
if (cidr.length === 0)
|
|
133
|
+
throw new Error('CIDR array is empty');
|
|
134
|
+
// Pick a random CIDR network
|
|
135
|
+
const network = cidr[Math.floor(Math.random() * cidr.length)];
|
|
136
|
+
// dbg('randomCIDRIp:network', network)
|
|
137
|
+
// Get the range of IPs in this CIDR
|
|
138
|
+
const start = network.first().toBigInt();
|
|
139
|
+
// dbg('randomCIDRIp:first', network.first().toString(),start)
|
|
140
|
+
const end = network.last().toBigInt();
|
|
141
|
+
// dbg('randomCIDRIp:last', network.last().toString(),end)
|
|
142
|
+
let range = end - start;
|
|
143
|
+
// dbg('randomCIDRIp:first:last', start, end)
|
|
144
|
+
// Generate a random Long between the start and end
|
|
145
|
+
// if start-end > Maximum integer number
|
|
146
|
+
// we need to use BigInt
|
|
147
|
+
if (range > BigInt(Number.MAX_SAFE_INTEGER))
|
|
148
|
+
range = (Number.MAX_SAFE_INTEGER);
|
|
149
|
+
const randomBigInt = BigInt(Math.floor(Math.random() * (Number(range) + 1))) + start;
|
|
150
|
+
// dbg('randomBigInt', randomBigInt)
|
|
151
|
+
// Convert the BigInt back to an IP address
|
|
152
|
+
const randomIp = ip6addr_1.default.parse(randomBigInt);
|
|
153
|
+
// dbg('randomCIDRIp', randomIp.toString())
|
|
154
|
+
return new IPAddress(randomIp.toString());
|
|
155
|
+
}
|
|
85
156
|
serialize() {
|
|
86
157
|
if (this.kind() === 4) {
|
|
87
158
|
// zero pad ipv4
|
|
@@ -158,4 +229,24 @@ class IPAddress {
|
|
|
158
229
|
}
|
|
159
230
|
}
|
|
160
231
|
exports.IPAddress = IPAddress;
|
|
232
|
+
IPAddress.loopback_cidrs4 = [
|
|
233
|
+
ip6addr_1.default.createCIDR('127.0.0.0/8'),
|
|
234
|
+
];
|
|
235
|
+
IPAddress.loopback_cidrs6 = [
|
|
236
|
+
ip6addr_1.default.createCIDR('::1/128') // yes ipv6 has single address
|
|
237
|
+
];
|
|
238
|
+
IPAddress.loopback_cidrs = IPAddress.loopback_cidrs4.concat(IPAddress.loopback_cidrs6);
|
|
239
|
+
IPAddress.lan_cidrs4 = [
|
|
240
|
+
ip6addr_1.default.createCIDR('10.0.0.0/8'),
|
|
241
|
+
ip6addr_1.default.createCIDR('172.16.0.0/12'),
|
|
242
|
+
ip6addr_1.default.createCIDR('192.168.0.0/16'),
|
|
243
|
+
];
|
|
244
|
+
IPAddress.lan_cidrs6 = [
|
|
245
|
+
ip6addr_1.default.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
|
|
246
|
+
ip6addr_1.default.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
|
|
247
|
+
];
|
|
248
|
+
IPAddress.lan_cidrs = IPAddress.lan_cidrs4.concat(IPAddress.lan_cidrs6);
|
|
249
|
+
IPAddress.local_cidrs = IPAddress.loopback_cidrs.concat(IPAddress.lan_cidrs);
|
|
250
|
+
IPAddress.local_cidrs4 = IPAddress.loopback_cidrs4.concat(IPAddress.lan_cidrs4);
|
|
251
|
+
IPAddress.local_cidrs6 = IPAddress.loopback_cidrs6.concat(IPAddress.lan_cidrs6);
|
|
161
252
|
//# sourceMappingURL=IPAddress.js.map
|
|
@@ -63,22 +63,22 @@ describe('IPAddress', () => {
|
|
|
63
63
|
})
|
|
64
64
|
|
|
65
65
|
it('randomly generated ipv4 serialization', () => {
|
|
66
|
-
for(let i = 0; i < 100; i++) {
|
|
66
|
+
for (let i = 0; i < 100; i++) {
|
|
67
67
|
const ip = randomIP()
|
|
68
68
|
expect(IPAddress.unserialize(IPAddress.fromString(ip).serialize()).toString()).toBe(ip)
|
|
69
69
|
}
|
|
70
70
|
})
|
|
71
71
|
|
|
72
72
|
it('randomly generated ipv6 serialization and unserialization', () => {
|
|
73
|
-
for(let i = 0; i < 100; i++) {
|
|
73
|
+
for (let i = 0; i < 100; i++) {
|
|
74
74
|
const ip = randomIP6()
|
|
75
75
|
let ip2 = IPAddress.unserialize(IPAddress.fromString(ip).serialize()).toString()
|
|
76
|
-
expect(ip6addr.compare(ip, ip2)).toEqual(0)
|
|
76
|
+
expect(ip6addr.compare(ip, ip2)).toEqual(0)
|
|
77
77
|
}
|
|
78
78
|
})
|
|
79
79
|
|
|
80
80
|
it('it should detect the kind of ip4', () => {
|
|
81
|
-
for(let i = 0; i < 100; i++)
|
|
81
|
+
for (let i = 0; i < 100; i++)
|
|
82
82
|
expect(IPAddress.randomIP4().kind()).toBe(4)
|
|
83
83
|
})
|
|
84
84
|
|
|
@@ -88,10 +88,10 @@ describe('IPAddress', () => {
|
|
|
88
88
|
|
|
89
89
|
it('randomPad return valid ipv4 results', () => {
|
|
90
90
|
let compared = 0
|
|
91
|
-
while(compared<100) {
|
|
91
|
+
while (compared < 100) {
|
|
92
92
|
const ip1 = IPAddress.randomIP4()
|
|
93
93
|
const ip2 = ip1.randomPad()
|
|
94
|
-
if (ip1.toString()!==ip2) { // find ips they are padded from the original
|
|
94
|
+
if (ip1.toString() !== ip2) { // find ips they are padded from the original
|
|
95
95
|
compared++
|
|
96
96
|
}
|
|
97
97
|
expect(IPAddress.validate(ip2)).toBe(true)
|
|
@@ -100,10 +100,10 @@ describe('IPAddress', () => {
|
|
|
100
100
|
|
|
101
101
|
it('compare ipv4 should detect equality even if they are padded', () => {
|
|
102
102
|
let compared = 0
|
|
103
|
-
while(compared<100) {
|
|
103
|
+
while (compared < 100) {
|
|
104
104
|
const ip1 = IPAddress.randomIP4()
|
|
105
105
|
const ip2 = ip1.randomPad()
|
|
106
|
-
if (ip1.toString()!==ip2) { // find ips they are padded from the original
|
|
106
|
+
if (ip1.toString() !== ip2) { // find ips they are padded from the original
|
|
107
107
|
compared++
|
|
108
108
|
}
|
|
109
109
|
expect(ip1.equals(IPAddress.fromString(ip2))).toBe(true)
|
|
@@ -137,20 +137,20 @@ describe('IPAddress IPv6', () => {
|
|
|
137
137
|
|
|
138
138
|
it('it should detect the kind of ip6', () => {
|
|
139
139
|
expect(new IPAddress('2605:2700:0000:0003:a800:00ff:fe10:f0d3').kind()).toBe(6);
|
|
140
|
-
for(let i = 0; i < 100; i++)
|
|
140
|
+
for (let i = 0; i < 100; i++)
|
|
141
141
|
expect(IPAddress.randomIP6().kind()).toBe(6)
|
|
142
142
|
})
|
|
143
143
|
|
|
144
144
|
it('randomPad return valid ipv6 results be compareable with equals', () => {
|
|
145
145
|
let compared = 0
|
|
146
|
-
while(compared<500) {
|
|
146
|
+
while (compared < 500) {
|
|
147
147
|
const ip1 = IPAddress.randomIP6()
|
|
148
148
|
const ip2 = ip1.randomPad()
|
|
149
149
|
expect(ip1.kind()).toBe(6)
|
|
150
|
-
if (ip1.toString()!==ip2) { // find ips they are padded from the original
|
|
150
|
+
if (ip1.toString() !== ip2) { // find ips they are padded from the original
|
|
151
151
|
compared++
|
|
152
152
|
}
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
expect(IPAddress.validate(ip2)).toBe(true)
|
|
155
155
|
expect(ip1.equals(IPAddress.fromString(ip2))).toBe(true)
|
|
156
156
|
}
|
|
@@ -173,16 +173,135 @@ describe('IPAddress asciiChecksum', () => {
|
|
|
173
173
|
})
|
|
174
174
|
|
|
175
175
|
it('it should always return a single character ipv4/v6', () => {
|
|
176
|
-
for(let i=0;i<10000;i++) {
|
|
176
|
+
for (let i = 0; i < 10000; i++) {
|
|
177
177
|
expect(new IPAddress(randomIP()).asciiChecksum().length).toBe(1)
|
|
178
178
|
expect(new IPAddress(randomIP6()).asciiChecksum().length).toBe(1)
|
|
179
179
|
}
|
|
180
180
|
})
|
|
181
181
|
|
|
182
|
-
it('it should return a-z0-9 ascii only',()=>{
|
|
183
|
-
for(let i=0;i<10000;i++) {
|
|
182
|
+
it('it should return a-z0-9 ascii only', () => {
|
|
183
|
+
for (let i = 0; i < 10000; i++) {
|
|
184
184
|
expect('abcdefghijklmnopqrstuvwxyz0123456789').toContain(new IPAddress(randomIP()).asciiChecksum())
|
|
185
185
|
expect('abcdefghijklmnopqrstuvwxyz0123456789').toContain(new IPAddress(randomIP6()).asciiChecksum())
|
|
186
186
|
}
|
|
187
187
|
})
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
describe('IPAddress partOfCIDR', () => {
|
|
191
|
+
it('should detect cidrs in ipv4', () => {
|
|
192
|
+
expect(IPAddress.partOfCIDR('127.0.0.1', [ip6addr.createCIDR('127.0.0.0/8')])).toBe(true)
|
|
193
|
+
expect(IPAddress.partOfCIDR('127.0.0.1', [ip6addr.createCIDR('128.0.0.0/8')])).toBe(false)
|
|
194
|
+
expect(IPAddress.partOfCIDR('127.0.0.1', [ip6addr.createCIDR('126.0.0.0/8')])).toBe(false)
|
|
195
|
+
})
|
|
196
|
+
it('should detect cidrs in ipv6', () => {
|
|
197
|
+
expect(IPAddress.partOfCIDR('::1', [ip6addr.createCIDR('::/8')])).toBe(true)
|
|
198
|
+
expect(IPAddress.partOfCIDR('::1', [ip6addr.createCIDR('2ff0::1:0/8')])).toBe(false)
|
|
199
|
+
expect(IPAddress.partOfCIDR('::1', [ip6addr.createCIDR('3ff0::2:0/8')])).toBe(false)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it('should also work non-static', () => {
|
|
203
|
+
expect(new IPAddress('::1').partOfCIDR([ip6addr.createCIDR('::/8')])).toBe(true)
|
|
204
|
+
})
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
describe('IPAddress randomCIDRIp', () => {
|
|
208
|
+
const testCount = 25000
|
|
209
|
+
|
|
210
|
+
it('"loopback" should return random loopback ip4/6', () => {
|
|
211
|
+
const stats:any={
|
|
212
|
+
'4':0,
|
|
213
|
+
'6':0
|
|
214
|
+
}
|
|
215
|
+
for(var i=0;i<testCount;i++) {
|
|
216
|
+
const rip = IPAddress.randomCIDRIp('loopback')
|
|
217
|
+
stats[rip.kind().toString()]++
|
|
218
|
+
expect(rip.isLoopbackIP()).toBe(true)
|
|
219
|
+
}
|
|
220
|
+
// we need to have at least 30% of ipv4 and ipv6
|
|
221
|
+
expect(stats['4']).toBeGreaterThan(testCount*0.3)
|
|
222
|
+
expect(stats['6']).toBeGreaterThan(testCount*0.3)
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
it('"loopback4" should return random loopback ip4', () => {
|
|
226
|
+
for(var i=0;i<testCount;i++) {
|
|
227
|
+
const rip = IPAddress.randomCIDRIp('loopback4')
|
|
228
|
+
expect(rip.kind()).toBe(4)
|
|
229
|
+
expect(rip.isLoopbackIP()).toBe(true)
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
it('"loopback6" should return random loopback ip6', () => {
|
|
235
|
+
for(var i=0;i<testCount;i++) {
|
|
236
|
+
const rip = IPAddress.randomCIDRIp('loopback6')
|
|
237
|
+
expect(rip.kind()).toBe(6)
|
|
238
|
+
expect(rip.isLoopbackIP()).toBe(true)
|
|
239
|
+
// ipv6 has single loopback address
|
|
240
|
+
expect(rip.toString()).toBe('::1')
|
|
241
|
+
}
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('"lan" should return random LAN ip4/6', () => {
|
|
245
|
+
const stats:any={
|
|
246
|
+
'4':0,
|
|
247
|
+
'6':0
|
|
248
|
+
}
|
|
249
|
+
for(var i=0;i<testCount;i++) {
|
|
250
|
+
const rip = IPAddress.randomCIDRIp('lan')
|
|
251
|
+
stats[rip.kind().toString()]++
|
|
252
|
+
// if (!rip.isLANIP()) console.log(rip.toString(),`must be lan but it is not`)
|
|
253
|
+
expect(rip.isLANIP()).toBe(true)
|
|
254
|
+
}
|
|
255
|
+
// we need to have at least 30% of ipv4 and ipv6
|
|
256
|
+
expect(stats['4']).toBeGreaterThan(testCount*0.3)
|
|
257
|
+
expect(stats['6']).toBeGreaterThan(testCount*0.3)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
it('"lan6" should return random lan ip6', () => {
|
|
262
|
+
for(var i=0;i<testCount;i++) {
|
|
263
|
+
const rip = IPAddress.randomCIDRIp('lan6')
|
|
264
|
+
expect(rip.kind()).toBe(6)
|
|
265
|
+
expect(rip.isLANIP()).toBe(true)
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
it('"lan4" should return random lan ip4', () => {
|
|
270
|
+
for(var i=0;i<testCount;i++) {
|
|
271
|
+
const rip = IPAddress.randomCIDRIp('lan4')
|
|
272
|
+
expect(rip.kind()).toBe(4)
|
|
273
|
+
expect(rip.isLANIP()).toBe(true)
|
|
274
|
+
}
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it('"local" should return random local ip4/6', () => {
|
|
278
|
+
const stats:any={
|
|
279
|
+
'4':0,
|
|
280
|
+
'6':0
|
|
281
|
+
}
|
|
282
|
+
for(var i=0;i<testCount;i++) {
|
|
283
|
+
const rip = IPAddress.randomCIDRIp('local')
|
|
284
|
+
stats[rip.kind().toString()]++
|
|
285
|
+
expect(rip.isLocalIP()).toBe(true)
|
|
286
|
+
}
|
|
287
|
+
// we need to have at least 30% of ipv4 and ipv6
|
|
288
|
+
expect(stats['4']).toBeGreaterThan(testCount*0.3)
|
|
289
|
+
expect(stats['6']).toBeGreaterThan(testCount*0.3)
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
it('"local4" should return random local ip4', () => {
|
|
293
|
+
for(var i=0;i<testCount;i++) {
|
|
294
|
+
const rip = IPAddress.randomCIDRIp('local4')
|
|
295
|
+
expect(rip.kind()).toBe(4)
|
|
296
|
+
expect(rip.isLocalIP()).toBe(true)
|
|
297
|
+
}
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
it('"local6" should return random local ip6', () => {
|
|
301
|
+
for(var i=0;i<testCount;i++) {
|
|
302
|
+
const rip = IPAddress.randomCIDRIp('local6')
|
|
303
|
+
expect(rip.kind()).toBe(6)
|
|
304
|
+
expect(rip.isLocalIP()).toBe(true)
|
|
305
|
+
}
|
|
306
|
+
})
|
|
188
307
|
})
|
package/ts/models/IPAddress.ts
CHANGED
|
@@ -1,11 +1,43 @@
|
|
|
1
|
-
import
|
|
1
|
+
import debug from 'debug'
|
|
2
|
+
import { randomIP, randomIP6, } from "./../"
|
|
2
3
|
import ip6addr, { Addr, ToStringOpts } from 'ip6addr'
|
|
4
|
+
import net from 'net'
|
|
3
5
|
const ip6 = require('ip6') // "url": "https://github.com/elgs/ip6"
|
|
6
|
+
const dbg = debug('_IPAddress')
|
|
7
|
+
dbg.enabled = true
|
|
4
8
|
// need version "ip6": "0.2.7",!!
|
|
5
9
|
|
|
6
10
|
export class IPAddress {
|
|
7
11
|
private _ip: Addr
|
|
8
12
|
|
|
13
|
+
public static loopback_cidrs4 = [
|
|
14
|
+
ip6addr.createCIDR('127.0.0.0/8'),
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
public static loopback_cidrs6 = [
|
|
18
|
+
ip6addr.createCIDR('::1/128') // yes ipv6 has single address
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
public static loopback_cidrs = IPAddress.loopback_cidrs4.concat(IPAddress.loopback_cidrs6)
|
|
22
|
+
|
|
23
|
+
public static lan_cidrs4 = [
|
|
24
|
+
ip6addr.createCIDR('10.0.0.0/8'),
|
|
25
|
+
ip6addr.createCIDR('172.16.0.0/12'),
|
|
26
|
+
ip6addr.createCIDR('192.168.0.0/16'),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
public static lan_cidrs6 = [
|
|
30
|
+
ip6addr.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
|
|
31
|
+
ip6addr.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
public static lan_cidrs = IPAddress.lan_cidrs4.concat(IPAddress.lan_cidrs6)
|
|
35
|
+
|
|
36
|
+
public static local_cidrs = IPAddress.loopback_cidrs.concat(IPAddress.lan_cidrs)
|
|
37
|
+
public static local_cidrs4 = IPAddress.loopback_cidrs4.concat(IPAddress.lan_cidrs4)
|
|
38
|
+
public static local_cidrs6 = IPAddress.loopback_cidrs6.concat(IPAddress.lan_cidrs6)
|
|
39
|
+
|
|
40
|
+
|
|
9
41
|
constructor(ip: string) { // may throw
|
|
10
42
|
if (ip === '-') ip = '0.0.0.0'
|
|
11
43
|
|
|
@@ -51,11 +83,34 @@ export class IPAddress {
|
|
|
51
83
|
}
|
|
52
84
|
|
|
53
85
|
public isLoopbackIP(): boolean {
|
|
54
|
-
return
|
|
86
|
+
return this.partOfCIDR(IPAddress.loopback_cidrs)
|
|
55
87
|
}
|
|
56
88
|
|
|
57
89
|
public isLANIP(): boolean {
|
|
58
|
-
return
|
|
90
|
+
return this.partOfCIDR(IPAddress.lan_cidrs)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
public isLocalIP(): boolean {
|
|
94
|
+
return this.partOfCIDR(IPAddress.local_cidrs)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
partOfCIDR(cidr_networks: ip6addr.CIDR[]): boolean {
|
|
98
|
+
const ipNormalized = this.toString()
|
|
99
|
+
let ipVersion = net.isIPv4(ipNormalized) ? 'ipv4' : 'ipv6'
|
|
100
|
+
for (let cidr of cidr_networks) {
|
|
101
|
+
if (!cidr) continue
|
|
102
|
+
let first = cidr.first()
|
|
103
|
+
if (first.kind() !== ipVersion) continue
|
|
104
|
+
if (cidr.contains(ipNormalized))
|
|
105
|
+
return true
|
|
106
|
+
}
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static partOfCIDR(_ip: string, cidr_networks: ip6addr.CIDR[]): boolean {
|
|
111
|
+
const ip = IPAddress.try(_ip)
|
|
112
|
+
if (ip === undefined) return false
|
|
113
|
+
return ip.partOfCIDR(cidr_networks)
|
|
59
114
|
}
|
|
60
115
|
|
|
61
116
|
public isPublicIP(): boolean {
|
|
@@ -86,6 +141,46 @@ export class IPAddress {
|
|
|
86
141
|
return new IPAddress(randomIP6())
|
|
87
142
|
}
|
|
88
143
|
|
|
144
|
+
|
|
145
|
+
public static randomCIDRIp(cidr: ip6addr.CIDR[] | 'loopback' | 'lan' | 'local' | 'loopback4' | 'loopback6' | 'lan4' | 'lan6' | 'local4' | 'local6'): IPAddress {
|
|
146
|
+
if (cidr === 'loopback') cidr = IPAddress.loopback_cidrs
|
|
147
|
+
if (cidr === 'loopback4') cidr = IPAddress.loopback_cidrs4
|
|
148
|
+
if (cidr === 'loopback6') cidr = IPAddress.loopback_cidrs6
|
|
149
|
+
if (cidr === 'lan') cidr = IPAddress.lan_cidrs
|
|
150
|
+
if (cidr === 'lan4') cidr = IPAddress.lan_cidrs4
|
|
151
|
+
if (cidr === 'lan6') cidr = IPAddress.lan_cidrs6
|
|
152
|
+
if (cidr === 'local') cidr = IPAddress.local_cidrs
|
|
153
|
+
if (cidr === 'local4') cidr = IPAddress.local_cidrs4
|
|
154
|
+
if (cidr === 'local6') cidr = IPAddress.local_cidrs6
|
|
155
|
+
// dbg('randomCIDRIp', cidr)
|
|
156
|
+
if (cidr.length === 0) throw new Error('CIDR array is empty')
|
|
157
|
+
// Pick a random CIDR network
|
|
158
|
+
const network = cidr[Math.floor(Math.random() * cidr.length)];
|
|
159
|
+
// dbg('randomCIDRIp:network', network)
|
|
160
|
+
// Get the range of IPs in this CIDR
|
|
161
|
+
const start = network.first().toBigInt()
|
|
162
|
+
// dbg('randomCIDRIp:first', network.first().toString(),start)
|
|
163
|
+
const end = network.last().toBigInt();
|
|
164
|
+
// dbg('randomCIDRIp:last', network.last().toString(),end)
|
|
165
|
+
let range : any = end-start
|
|
166
|
+
// dbg('randomCIDRIp:first:last', start, end)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
// Generate a random Long between the start and end
|
|
170
|
+
// if start-end > Maximum integer number
|
|
171
|
+
// we need to use BigInt
|
|
172
|
+
if (range > BigInt(Number.MAX_SAFE_INTEGER)) range=(Number.MAX_SAFE_INTEGER)
|
|
173
|
+
|
|
174
|
+
const randomBigInt = BigInt(Math.floor(Math.random() * (Number(range) + 1))) + start;
|
|
175
|
+
// dbg('randomBigInt', randomBigInt)
|
|
176
|
+
|
|
177
|
+
// Convert the BigInt back to an IP address
|
|
178
|
+
const randomIp = ip6addr.parse(randomBigInt)
|
|
179
|
+
// dbg('randomCIDRIp', randomIp.toString())
|
|
180
|
+
|
|
181
|
+
return new IPAddress(randomIp.toString())
|
|
182
|
+
}
|
|
183
|
+
|
|
89
184
|
public serialize(): string {
|
|
90
185
|
if (this.kind() === 4) {
|
|
91
186
|
// zero pad ipv4
|
package/tsconfig.json
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
declare module 'ip6addr' {
|
|
2
|
+
export interface ToStringOpts {
|
|
3
|
+
format?: "auto" | "v4" | "v4-mapped" | "v6" | undefined;
|
|
4
|
+
zeroElide?: boolean | undefined;
|
|
5
|
+
zeroPad?: boolean | undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Addr {
|
|
9
|
+
kind: () => "ipv4" | "ipv6";
|
|
10
|
+
toString: (opts?: ToStringOpts) => string;
|
|
11
|
+
toBuffer: (buff?: Uint8Array) => Uint8Array;
|
|
12
|
+
toLong: () => number;
|
|
13
|
+
toBigInt: () => bigint;
|
|
14
|
+
offset: (num: number) => Addr | null;
|
|
15
|
+
compare: (other: string | Addr) => number;
|
|
16
|
+
clone: () => Addr;
|
|
17
|
+
and: (input: string | Addr) => Addr;
|
|
18
|
+
or: (input: string | Addr) => Addr;
|
|
19
|
+
not: () => Addr;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface AddrRange {
|
|
23
|
+
contains: (input: string | Addr) => boolean;
|
|
24
|
+
first: () => Addr;
|
|
25
|
+
last: () => Addr;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface CIDR extends AddrRange {
|
|
29
|
+
broadcast: () => Addr;
|
|
30
|
+
compare: (other: string | CIDR) => number;
|
|
31
|
+
prefixLength: (format?: "auto" | "v4" | "v6") => number;
|
|
32
|
+
address: () => Addr;
|
|
33
|
+
toString: (opts?: ToStringOpts) => string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function compare(addr1: string | Addr, addr2: string | Addr): number;
|
|
37
|
+
|
|
38
|
+
export function compareCIDR(cidr1: string | CIDR, cidr2: string | CIDR): number;
|
|
39
|
+
|
|
40
|
+
export function createAddrRange(begin: string | Addr, end: string | Addr): AddrRange;
|
|
41
|
+
|
|
42
|
+
export function createCIDR(addr: string | Addr, len?: number): CIDR;
|
|
43
|
+
|
|
44
|
+
export function parse(input: string | number | Addr | BigInt): Addr;
|
|
45
|
+
|
|
46
|
+
}
|