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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mybase",
3
- "version": "1.1.29",
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": "^0.2.5",
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",
@@ -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
- const private_network_cidrs = [ip6addr_1.default.createCIDR('10.0.0.0/8'),
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
@@ -1,25 +1,17 @@
1
1
  import ip6addr from 'ip6addr'
2
2
  import net from 'net'
3
3
 
4
- const private_network_cidrs = [ip6addr.createCIDR('10.0.0.0/8')
5
- ,ip6addr.createCIDR('172.16.0.0/12')
6
- ,ip6addr.createCIDR('192.168.0.0/16')
7
- ,ip6addr.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
8
- ,ip6addr.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
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) === 0) return false
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
+ }
@@ -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
- const local_network_cidrs = [ip6addr_1.default.createCIDR('127.0.0.0/8'),
10
- ip6addr_1.default.createCIDR('::1/128')];
11
- function normalizeIp(ip) {
12
- // also support ipv6
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
@@ -1,21 +1,14 @@
1
1
  import ip6addr from 'ip6addr'
2
2
  import net from 'net'
3
3
 
4
- const local_network_cidrs = [ip6addr.createCIDR('127.0.0.0/8')
5
- ,ip6addr.createCIDR('::1/128')]
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) === 0) return false
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
@@ -2,6 +2,6 @@ import * as IMPORTS from "./index";
2
2
 
3
3
  test('exports', () => {
4
4
  for(let fn of Object.values(IMPORTS)) {
5
- expect(typeof fn).toBe('function')
5
+ expect(typeof fn=='function' || typeof fn==='object').toBe(true)
6
6
  }
7
7
  })
@@ -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 (0, __1.isLoopbackIP)(this._ip.toString());
58
+ return this.partOfCIDR(IPAddress.loopback_cidrs);
55
59
  }
56
60
  isLANIP() {
57
- return (0, __1.isLANIp)(this._ip.toString());
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
  })
@@ -1,11 +1,43 @@
1
- import { randomIP, randomIP6, isLoopbackIP, isLANIp } from "./../"
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 isLoopbackIP(this._ip.toString())
86
+ return this.partOfCIDR(IPAddress.loopback_cidrs)
55
87
  }
56
88
 
57
89
  public isLANIP(): boolean {
58
- return isLANIp(this._ip.toString())
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
@@ -26,7 +26,8 @@
26
26
  "@root/*": ["./*"],
27
27
  "@models/*": ["./models/*"],
28
28
  "@inc/*": ["./inc/ts/*"]
29
- }
29
+ },
30
+ "typeRoots": ["./node_modules/@types", "./types/"]
30
31
  },
31
32
  "exclude": [
32
33
  "**/*.test.ts"
@@ -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
+ }