mybase 1.1.29 → 1.1.31

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.31",
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,16 +4,24 @@ 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) {
13
17
  if (ip === '-')
14
- ip = '0.0.0.0';
18
+ ip = '0.0.0.0'; // is this really required?
15
19
  try {
16
20
  this._ip = ip6addr_1.default.parse(ip);
21
+ if (this._ip._attrs.ipv4Mapped) {
22
+ // we wany to convert it to ipv4
23
+ this._ip = ip6addr_1.default.parse(this._ip.toString({ format: 'v4' }));
24
+ }
17
25
  }
18
26
  catch (err) {
19
27
  if (err instanceof Error)
@@ -21,6 +29,9 @@ class IPAddress {
21
29
  throw err;
22
30
  }
23
31
  }
32
+ abbreviated() {
33
+ return this.toString(); // default behaviour of ip6addr
34
+ }
24
35
  toString(opts = { format: 'auto', zeroElide: false, zeroPad: false }) {
25
36
  return this._ip.toString();
26
37
  }
@@ -51,10 +62,33 @@ class IPAddress {
51
62
  return new IPAddress('0.0.0.0');
52
63
  }
53
64
  isLoopbackIP() {
54
- return (0, __1.isLoopbackIP)(this._ip.toString());
65
+ return this.partOfCIDR(IPAddress.loopback_cidrs);
55
66
  }
56
67
  isLANIP() {
57
- return (0, __1.isLANIp)(this._ip.toString());
68
+ return this.partOfCIDR(IPAddress.lan_cidrs);
69
+ }
70
+ isLocalIP() {
71
+ return this.partOfCIDR(IPAddress.local_cidrs);
72
+ }
73
+ partOfCIDR(cidr_networks) {
74
+ const ipNormalized = this.toString();
75
+ let ipVersion = net_1.default.isIPv4(ipNormalized) ? 'ipv4' : 'ipv6';
76
+ for (let cidr of cidr_networks) {
77
+ if (!cidr)
78
+ continue;
79
+ let first = cidr.first();
80
+ if (first.kind() !== ipVersion)
81
+ continue;
82
+ if (cidr.contains(ipNormalized))
83
+ return true;
84
+ }
85
+ return false;
86
+ }
87
+ static partOfCIDR(_ip, cidr_networks) {
88
+ const ip = IPAddress.try(_ip);
89
+ if (ip === undefined)
90
+ return false;
91
+ return ip.partOfCIDR(cidr_networks);
58
92
  }
59
93
  isPublicIP() {
60
94
  return this.toString() !== '0.0.0.0' && !this.isLoopbackIP() && !this.isLANIP();
@@ -82,6 +116,50 @@ class IPAddress {
82
116
  static randomIP6() {
83
117
  return new IPAddress((0, __1.randomIP6)());
84
118
  }
119
+ static randomCIDRIp(cidr) {
120
+ if (cidr === 'loopback')
121
+ cidr = IPAddress.loopback_cidrs;
122
+ if (cidr === 'loopback4')
123
+ cidr = IPAddress.loopback_cidrs4;
124
+ if (cidr === 'loopback6')
125
+ cidr = IPAddress.loopback_cidrs6;
126
+ if (cidr === 'lan')
127
+ cidr = IPAddress.lan_cidrs;
128
+ if (cidr === 'lan4')
129
+ cidr = IPAddress.lan_cidrs4;
130
+ if (cidr === 'lan6')
131
+ cidr = IPAddress.lan_cidrs6;
132
+ if (cidr === 'local')
133
+ cidr = IPAddress.local_cidrs;
134
+ if (cidr === 'local4')
135
+ cidr = IPAddress.local_cidrs4;
136
+ if (cidr === 'local6')
137
+ cidr = IPAddress.local_cidrs6;
138
+ // dbg('randomCIDRIp', cidr)
139
+ if (cidr.length === 0)
140
+ throw new Error('CIDR array is empty');
141
+ // Pick a random CIDR network
142
+ const network = cidr[Math.floor(Math.random() * cidr.length)];
143
+ // dbg('randomCIDRIp:network', network)
144
+ // Get the range of IPs in this CIDR
145
+ const start = network.first().toBigInt();
146
+ // dbg('randomCIDRIp:first', network.first().toString(),start)
147
+ const end = network.last().toBigInt();
148
+ // dbg('randomCIDRIp:last', network.last().toString(),end)
149
+ let range = end - start;
150
+ // dbg('randomCIDRIp:first:last', start, end)
151
+ // Generate a random Long between the start and end
152
+ // if start-end > Maximum integer number
153
+ // we need to use BigInt
154
+ if (range > BigInt(Number.MAX_SAFE_INTEGER))
155
+ range = (Number.MAX_SAFE_INTEGER);
156
+ const randomBigInt = BigInt(Math.floor(Math.random() * (Number(range) + 1))) + start;
157
+ // dbg('randomBigInt', randomBigInt)
158
+ // Convert the BigInt back to an IP address
159
+ const randomIp = ip6addr_1.default.parse(randomBigInt);
160
+ // dbg('randomCIDRIp', randomIp.toString())
161
+ return new IPAddress(randomIp.toString());
162
+ }
85
163
  serialize() {
86
164
  if (this.kind() === 4) {
87
165
  // zero pad ipv4
@@ -110,11 +188,6 @@ class IPAddress {
110
188
  return this._ip.toString();
111
189
  return ip6.normalize(this._ip.toString());
112
190
  }
113
- abbreviated() {
114
- if (this.kind() === 4)
115
- return this._ip.toString();
116
- return ip6.abbreviate(this._ip.toString());
117
- }
118
191
  padIp6() {
119
192
  const hextets = this.normalized().split(':'); // we need to have the full form
120
193
  const paddedHextets = hextets.map(hextet => {
@@ -158,4 +231,24 @@ class IPAddress {
158
231
  }
159
232
  }
160
233
  exports.IPAddress = IPAddress;
234
+ IPAddress.loopback_cidrs4 = [
235
+ ip6addr_1.default.createCIDR('127.0.0.0/8'),
236
+ ];
237
+ IPAddress.loopback_cidrs6 = [
238
+ ip6addr_1.default.createCIDR('::1/128') // yes ipv6 has single address
239
+ ];
240
+ IPAddress.loopback_cidrs = IPAddress.loopback_cidrs4.concat(IPAddress.loopback_cidrs6);
241
+ IPAddress.lan_cidrs4 = [
242
+ ip6addr_1.default.createCIDR('10.0.0.0/8'),
243
+ ip6addr_1.default.createCIDR('172.16.0.0/12'),
244
+ ip6addr_1.default.createCIDR('192.168.0.0/16'),
245
+ ];
246
+ IPAddress.lan_cidrs6 = [
247
+ ip6addr_1.default.createCIDR('fd00::/8'), // Reserved by IETF for future use, but not currently in active use.
248
+ ip6addr_1.default.createCIDR('fc00::/8'), // The range currently in use for local communications within a site or organization.
249
+ ];
250
+ IPAddress.lan_cidrs = IPAddress.lan_cidrs4.concat(IPAddress.lan_cidrs6);
251
+ IPAddress.local_cidrs = IPAddress.loopback_cidrs.concat(IPAddress.lan_cidrs);
252
+ IPAddress.local_cidrs4 = IPAddress.loopback_cidrs4.concat(IPAddress.lan_cidrs4);
253
+ IPAddress.local_cidrs6 = IPAddress.loopback_cidrs6.concat(IPAddress.lan_cidrs6);
161
254
  //# 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,16 +100,102 @@ 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)
110
110
  }
111
111
  })
112
112
 
113
+ it('normalized should normalize ipv4 ips properly', () => {
114
+ expect(new IPAddress('127.0.0.1').normalized()).toBe('127.0.0.1')
115
+ expect(new IPAddress('127.00.0.1').normalized()).toBe('127.0.0.1')
116
+ expect(new IPAddress('127.000.00.1').normalized()).toBe('127.0.0.1')
117
+ expect(new IPAddress('127.0.00.00001').normalized()).toBe('127.0.0.1')
118
+ })
119
+
120
+ it('normalized should normalize ipv6 ips properly', () => {
121
+ expect(new IPAddress('::1').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
122
+ expect(new IPAddress('::01').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
123
+ expect(new IPAddress('::001').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
124
+ expect(new IPAddress('::0001').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
125
+ expect(new IPAddress('::000001').normalized()).toBe('0000:0000:0000:0000:0000:0000:0000:0001')
126
+ expect(new IPAddress('::1:1').normalized()).toBe('0000:0000:0000:0000:0000:0000:0001:0001')
127
+ expect(new IPAddress('::2:1').normalized()).toBe('0000:0000:0000:0000:0000:0000:0002:0001')
128
+
129
+
130
+ expect(new IPAddress('1::1').normalized()).toBe('0001:0000:0000:0000:0000:0000:0000:0001')
131
+ expect(new IPAddress('2::01').normalized()).toBe('0002:0000:0000:0000:0000:0000:0000:0001')
132
+ expect(new IPAddress('3::001').normalized()).toBe('0003:0000:0000:0000:0000:0000:0000:0001')
133
+ expect(new IPAddress('4::0001').normalized()).toBe('0004:0000:0000:0000:0000:0000:0000:0001')
134
+ expect(new IPAddress('5::000001').normalized()).toBe('0005:0000:0000:0000:0000:0000:0000:0001')
135
+ expect(new IPAddress('6::1:1').normalized()).toBe('0006:0000:0000:0000:0000:0000:0001:0001')
136
+ expect(new IPAddress('7::2:1').normalized()).toBe('0007:0000:0000:0000:0000:0000:0002:0001')
137
+ })
138
+
139
+
140
+ it('abbreviated should abbreviate ipv6 ips properly', () => {
141
+ expect(new IPAddress('::1').abbreviated()).toBe('::1')
142
+ expect(new IPAddress('::01').abbreviated()).toBe('::1')
143
+ expect(new IPAddress('::001').abbreviated()).toBe('::1')
144
+ expect(new IPAddress('::0001').abbreviated()).toBe('::1')
145
+ expect(new IPAddress('::000001').abbreviated()).toBe('::1')
146
+ expect(new IPAddress('0000:0000:0000:0000:0000:0000:0001:0001').abbreviated()).toBe('::1:1')
147
+ expect(new IPAddress('0000:0000:0000:0000:0000:0000:0002:0001').abbreviated()).toBe('::2:1')
148
+
149
+ expect(new IPAddress('2001:0db8:0001:0002:0003:0004:0005:0006').abbreviated()).toBe('2001:db8:1:2:3:4:5:6')
150
+ expect(new IPAddress('1:0000:0000::0000:0000:0000:0001').abbreviated()).toBe('1::1')
151
+ expect(new IPAddress('0001:0000:0000:0000:0000:0000:0000:0001').abbreviated()).toBe('1::1')
152
+ expect(new IPAddress('0002:0000:0000:0000:0000::0000:0001').abbreviated()).toBe('2::1')
153
+ expect(new IPAddress('0003:0000:0000:0000:0000:0000:0000:0001').abbreviated()).toBe('3::1')
154
+ expect(new IPAddress('0004::0000:0000:0000:0000:0000:0001').abbreviated()).toBe('4::1')
155
+ expect(new IPAddress('0005:0000:0000:0000:0000:0000:0000:0001').abbreviated()).toBe('5::1')
156
+ expect(new IPAddress('0006:0000:0000::0000:0000:0001:0001').abbreviated()).toBe('6::1:1')
157
+ expect(new IPAddress('0007:0000:0000:0000:0000::0002:0001').abbreviated()).toBe('7::2:1')
158
+ })
159
+
160
+ it('abbreviated should abbreviate ipv4 ips properly', () => {
161
+ expect(new IPAddress('127.00.000.1').abbreviated()).toBe('127.0.0.1')
162
+ expect(new IPAddress('127.0.00.00001').abbreviated()).toBe('127.0.0.1')
163
+ expect(new IPAddress('127.0000.0.00001').abbreviated()).toBe('127.0.0.1')
164
+ expect(new IPAddress('0.0000.0.00000').abbreviated()).toBe('0.0.0.0')
165
+ })
166
+ it('abbreviated should abbreviate ipv4-mapped ips properly', () => {
167
+ expect(new IPAddress('::ffff:127.00.000.1').abbreviated()).toBe('127.0.0.1')
168
+ expect(new IPAddress('::ffff:127.0.00.00001').abbreviated()).toBe('127.0.0.1')
169
+ expect(new IPAddress('::ffff:127.0000.0.00001').abbreviated()).toBe('127.0.0.1')
170
+ expect(new IPAddress('0::ffff:127.0000.0.00001').abbreviated()).toBe('127.0.0.1')
171
+ expect(new IPAddress('0:0:0::ffff:127.0000.0.00001').abbreviated()).toBe('127.0.0.1')
172
+ expect(new IPAddress('::ffff:0.0000.0.00000').abbreviated()).toBe('0.0.0.0')
173
+ })
174
+
175
+ it('toString() IPv4-mapped IPv6 address should be returned as ipv4', () => {
176
+ expect(new IPAddress('::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
177
+ expect(new IPAddress('0::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
178
+ expect(new IPAddress('00::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
179
+ expect(new IPAddress('0:00::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
180
+ expect(new IPAddress('0:0:0::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
181
+ })
182
+
183
+ it('kind() IPv4-mapped IPv6 address should be returned as ipv4', () => {
184
+ expect(new IPAddress('::ffff:127.0.00.00001').kind()).toBe(4)
185
+ expect(new IPAddress('0::ffff:127.0.00.00001').kind()).toBe(4)
186
+ expect(new IPAddress('00::ffff:127.0.00.00001').kind()).toBe(4)
187
+ expect(new IPAddress('0:00::ffff:127.0.00.00001').kind()).toBe(4)
188
+ expect(new IPAddress('0:0:0::ffff:127.0.00.00001').kind()).toBe(4)
189
+ })
190
+
191
+ it('IPv4-mapps Addresses should be converted to Ipv4 at constructor', () => {
192
+ expect(new IPAddress('::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
193
+ expect(new IPAddress('0::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
194
+ expect(new IPAddress('00::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
195
+ expect(new IPAddress('0:00::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
196
+ expect(new IPAddress('0:0:0::ffff:127.0.00.00001').toString()).toBe('127.0.0.1')
197
+ })
198
+
113
199
  });
114
200
 
115
201
  describe('IPAddress IPv6', () => {
@@ -137,20 +223,20 @@ describe('IPAddress IPv6', () => {
137
223
 
138
224
  it('it should detect the kind of ip6', () => {
139
225
  expect(new IPAddress('2605:2700:0000:0003:a800:00ff:fe10:f0d3').kind()).toBe(6);
140
- for(let i = 0; i < 100; i++)
226
+ for (let i = 0; i < 100; i++)
141
227
  expect(IPAddress.randomIP6().kind()).toBe(6)
142
228
  })
143
229
 
144
230
  it('randomPad return valid ipv6 results be compareable with equals', () => {
145
231
  let compared = 0
146
- while(compared<500) {
232
+ while (compared < 500) {
147
233
  const ip1 = IPAddress.randomIP6()
148
234
  const ip2 = ip1.randomPad()
149
235
  expect(ip1.kind()).toBe(6)
150
- if (ip1.toString()!==ip2) { // find ips they are padded from the original
236
+ if (ip1.toString() !== ip2) { // find ips they are padded from the original
151
237
  compared++
152
238
  }
153
-
239
+
154
240
  expect(IPAddress.validate(ip2)).toBe(true)
155
241
  expect(ip1.equals(IPAddress.fromString(ip2))).toBe(true)
156
242
  }
@@ -173,16 +259,135 @@ describe('IPAddress asciiChecksum', () => {
173
259
  })
174
260
 
175
261
  it('it should always return a single character ipv4/v6', () => {
176
- for(let i=0;i<10000;i++) {
262
+ for (let i = 0; i < 10000; i++) {
177
263
  expect(new IPAddress(randomIP()).asciiChecksum().length).toBe(1)
178
264
  expect(new IPAddress(randomIP6()).asciiChecksum().length).toBe(1)
179
265
  }
180
266
  })
181
267
 
182
- it('it should return a-z0-9 ascii only',()=>{
183
- for(let i=0;i<10000;i++) {
268
+ it('it should return a-z0-9 ascii only', () => {
269
+ for (let i = 0; i < 10000; i++) {
184
270
  expect('abcdefghijklmnopqrstuvwxyz0123456789').toContain(new IPAddress(randomIP()).asciiChecksum())
185
271
  expect('abcdefghijklmnopqrstuvwxyz0123456789').toContain(new IPAddress(randomIP6()).asciiChecksum())
186
272
  }
187
273
  })
274
+ })
275
+
276
+ describe('IPAddress partOfCIDR', () => {
277
+ it('should detect cidrs in ipv4', () => {
278
+ expect(IPAddress.partOfCIDR('127.0.0.1', [ip6addr.createCIDR('127.0.0.0/8')])).toBe(true)
279
+ expect(IPAddress.partOfCIDR('127.0.0.1', [ip6addr.createCIDR('128.0.0.0/8')])).toBe(false)
280
+ expect(IPAddress.partOfCIDR('127.0.0.1', [ip6addr.createCIDR('126.0.0.0/8')])).toBe(false)
281
+ })
282
+ it('should detect cidrs in ipv6', () => {
283
+ expect(IPAddress.partOfCIDR('::1', [ip6addr.createCIDR('::/8')])).toBe(true)
284
+ expect(IPAddress.partOfCIDR('::1', [ip6addr.createCIDR('2ff0::1:0/8')])).toBe(false)
285
+ expect(IPAddress.partOfCIDR('::1', [ip6addr.createCIDR('3ff0::2:0/8')])).toBe(false)
286
+ })
287
+
288
+ it('should also work non-static', () => {
289
+ expect(new IPAddress('::1').partOfCIDR([ip6addr.createCIDR('::/8')])).toBe(true)
290
+ })
291
+ })
292
+
293
+ describe('IPAddress randomCIDRIp', () => {
294
+ const testCount = 25000
295
+
296
+ it('"loopback" should return random loopback ip4/6', () => {
297
+ const stats:any={
298
+ '4':0,
299
+ '6':0
300
+ }
301
+ for(var i=0;i<testCount;i++) {
302
+ const rip = IPAddress.randomCIDRIp('loopback')
303
+ stats[rip.kind().toString()]++
304
+ expect(rip.isLoopbackIP()).toBe(true)
305
+ }
306
+ // we need to have at least 30% of ipv4 and ipv6
307
+ expect(stats['4']).toBeGreaterThan(testCount*0.3)
308
+ expect(stats['6']).toBeGreaterThan(testCount*0.3)
309
+ })
310
+
311
+ it('"loopback4" should return random loopback ip4', () => {
312
+ for(var i=0;i<testCount;i++) {
313
+ const rip = IPAddress.randomCIDRIp('loopback4')
314
+ expect(rip.kind()).toBe(4)
315
+ expect(rip.isLoopbackIP()).toBe(true)
316
+ }
317
+ })
318
+
319
+
320
+ it('"loopback6" should return random loopback ip6', () => {
321
+ for(var i=0;i<testCount;i++) {
322
+ const rip = IPAddress.randomCIDRIp('loopback6')
323
+ expect(rip.kind()).toBe(6)
324
+ expect(rip.isLoopbackIP()).toBe(true)
325
+ // ipv6 has single loopback address
326
+ expect(rip.toString()).toBe('::1')
327
+ }
328
+ })
329
+
330
+ it('"lan" should return random LAN ip4/6', () => {
331
+ const stats:any={
332
+ '4':0,
333
+ '6':0
334
+ }
335
+ for(var i=0;i<testCount;i++) {
336
+ const rip = IPAddress.randomCIDRIp('lan')
337
+ stats[rip.kind().toString()]++
338
+ // if (!rip.isLANIP()) console.log(rip.toString(),`must be lan but it is not`)
339
+ expect(rip.isLANIP()).toBe(true)
340
+ }
341
+ // we need to have at least 30% of ipv4 and ipv6
342
+ expect(stats['4']).toBeGreaterThan(testCount*0.3)
343
+ expect(stats['6']).toBeGreaterThan(testCount*0.3)
344
+ })
345
+
346
+
347
+ it('"lan6" should return random lan ip6', () => {
348
+ for(var i=0;i<testCount;i++) {
349
+ const rip = IPAddress.randomCIDRIp('lan6')
350
+ expect(rip.kind()).toBe(6)
351
+ expect(rip.isLANIP()).toBe(true)
352
+ }
353
+ })
354
+
355
+ it('"lan4" should return random lan ip4', () => {
356
+ for(var i=0;i<testCount;i++) {
357
+ const rip = IPAddress.randomCIDRIp('lan4')
358
+ expect(rip.kind()).toBe(4)
359
+ expect(rip.isLANIP()).toBe(true)
360
+ }
361
+ })
362
+
363
+ it('"local" should return random local ip4/6', () => {
364
+ const stats:any={
365
+ '4':0,
366
+ '6':0
367
+ }
368
+ for(var i=0;i<testCount;i++) {
369
+ const rip = IPAddress.randomCIDRIp('local')
370
+ stats[rip.kind().toString()]++
371
+ expect(rip.isLocalIP()).toBe(true)
372
+ }
373
+ // we need to have at least 30% of ipv4 and ipv6
374
+ expect(stats['4']).toBeGreaterThan(testCount*0.3)
375
+ expect(stats['6']).toBeGreaterThan(testCount*0.3)
376
+ })
377
+
378
+ it('"local4" should return random local ip4', () => {
379
+ for(var i=0;i<testCount;i++) {
380
+ const rip = IPAddress.randomCIDRIp('local4')
381
+ expect(rip.kind()).toBe(4)
382
+ expect(rip.isLocalIP()).toBe(true)
383
+ }
384
+ })
385
+
386
+ it('"local6" should return random local ip6', () => {
387
+ for(var i=0;i<testCount;i++) {
388
+ const rip = IPAddress.randomCIDRIp('local6')
389
+ expect(rip.kind()).toBe(6)
390
+ expect(rip.isLocalIP()).toBe(true)
391
+ }
392
+ })
188
393
  })
@@ -1,16 +1,51 @@
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
 
9
- constructor(ip: string) { // may throw
10
- if (ip === '-') ip = '0.0.0.0'
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
+
11
40
 
41
+ constructor(ip: string) { // may throw
42
+ if (ip === '-') ip = '0.0.0.0' // is this really required?
12
43
  try {
13
44
  this._ip = ip6addr.parse(ip)
45
+ if (this._ip._attrs.ipv4Mapped) {
46
+ // we wany to convert it to ipv4
47
+ this._ip = ip6addr.parse(this._ip.toString({ format: 'v4' }))
48
+ }
14
49
  } catch (err) {
15
50
  if (err instanceof Error)
16
51
  throw new Error(`IPAddress: '${ip}' Error: ${err.message}`)
@@ -18,7 +53,12 @@ export class IPAddress {
18
53
  }
19
54
  }
20
55
 
21
- public toString(opts: ToStringOpts = { format: 'auto', zeroElide: false, zeroPad: false }): string {
56
+
57
+ public abbreviated(): string {
58
+ return this.toString() // default behaviour of ip6addr
59
+ }
60
+
61
+ public toString(opts: ToStringOpts = { format: 'auto', zeroElide: false, zeroPad: false }): string {
22
62
  return this._ip.toString()
23
63
  }
24
64
 
@@ -51,11 +91,34 @@ export class IPAddress {
51
91
  }
52
92
 
53
93
  public isLoopbackIP(): boolean {
54
- return isLoopbackIP(this._ip.toString())
94
+ return this.partOfCIDR(IPAddress.loopback_cidrs)
55
95
  }
56
96
 
57
97
  public isLANIP(): boolean {
58
- return isLANIp(this._ip.toString())
98
+ return this.partOfCIDR(IPAddress.lan_cidrs)
99
+ }
100
+
101
+ public isLocalIP(): boolean {
102
+ return this.partOfCIDR(IPAddress.local_cidrs)
103
+ }
104
+
105
+ partOfCIDR(cidr_networks: ip6addr.CIDR[]): boolean {
106
+ const ipNormalized = this.toString()
107
+ let ipVersion = net.isIPv4(ipNormalized) ? 'ipv4' : 'ipv6'
108
+ for (let cidr of cidr_networks) {
109
+ if (!cidr) continue
110
+ let first = cidr.first()
111
+ if (first.kind() !== ipVersion) continue
112
+ if (cidr.contains(ipNormalized))
113
+ return true
114
+ }
115
+ return false
116
+ }
117
+
118
+ static partOfCIDR(_ip: string, cidr_networks: ip6addr.CIDR[]): boolean {
119
+ const ip = IPAddress.try(_ip)
120
+ if (ip === undefined) return false
121
+ return ip.partOfCIDR(cidr_networks)
59
122
  }
60
123
 
61
124
  public isPublicIP(): boolean {
@@ -86,6 +149,46 @@ export class IPAddress {
86
149
  return new IPAddress(randomIP6())
87
150
  }
88
151
 
152
+
153
+ public static randomCIDRIp(cidr: ip6addr.CIDR[] | 'loopback' | 'lan' | 'local' | 'loopback4' | 'loopback6' | 'lan4' | 'lan6' | 'local4' | 'local6'): IPAddress {
154
+ if (cidr === 'loopback') cidr = IPAddress.loopback_cidrs
155
+ if (cidr === 'loopback4') cidr = IPAddress.loopback_cidrs4
156
+ if (cidr === 'loopback6') cidr = IPAddress.loopback_cidrs6
157
+ if (cidr === 'lan') cidr = IPAddress.lan_cidrs
158
+ if (cidr === 'lan4') cidr = IPAddress.lan_cidrs4
159
+ if (cidr === 'lan6') cidr = IPAddress.lan_cidrs6
160
+ if (cidr === 'local') cidr = IPAddress.local_cidrs
161
+ if (cidr === 'local4') cidr = IPAddress.local_cidrs4
162
+ if (cidr === 'local6') cidr = IPAddress.local_cidrs6
163
+ // dbg('randomCIDRIp', cidr)
164
+ if (cidr.length === 0) throw new Error('CIDR array is empty')
165
+ // Pick a random CIDR network
166
+ const network = cidr[Math.floor(Math.random() * cidr.length)];
167
+ // dbg('randomCIDRIp:network', network)
168
+ // Get the range of IPs in this CIDR
169
+ const start = network.first().toBigInt()
170
+ // dbg('randomCIDRIp:first', network.first().toString(),start)
171
+ const end = network.last().toBigInt();
172
+ // dbg('randomCIDRIp:last', network.last().toString(),end)
173
+ let range : any = end-start
174
+ // dbg('randomCIDRIp:first:last', start, end)
175
+
176
+
177
+ // Generate a random Long between the start and end
178
+ // if start-end > Maximum integer number
179
+ // we need to use BigInt
180
+ if (range > BigInt(Number.MAX_SAFE_INTEGER)) range=(Number.MAX_SAFE_INTEGER)
181
+
182
+ const randomBigInt = BigInt(Math.floor(Math.random() * (Number(range) + 1))) + start;
183
+ // dbg('randomBigInt', randomBigInt)
184
+
185
+ // Convert the BigInt back to an IP address
186
+ const randomIp = ip6addr.parse(randomBigInt)
187
+ // dbg('randomCIDRIp', randomIp.toString())
188
+
189
+ return new IPAddress(randomIp.toString())
190
+ }
191
+
89
192
  public serialize(): string {
90
193
  if (this.kind() === 4) {
91
194
  // zero pad ipv4
@@ -118,10 +221,6 @@ export class IPAddress {
118
221
  return ip6.normalize(this._ip.toString())
119
222
  }
120
223
 
121
- public abbreviated(): string {
122
- if (this.kind() === 4) return this._ip.toString()
123
- return ip6.abbreviate(this._ip.toString())
124
- }
125
224
 
126
225
  private padIp6(): string {
127
226
  const hextets = this.normalized().split(':') // we need to have the full form
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,52 @@
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 AddrAttributes {
9
+ ipv4Bare:boolean;
10
+ ipv4Mapped: boolean;
11
+ }
12
+
13
+ export interface Addr {
14
+ _attrs: AddrAttributes;
15
+ kind: () => "ipv4" | "ipv6";
16
+ toString: (opts?: ToStringOpts) => string;
17
+ toBuffer: (buff?: Uint8Array) => Uint8Array;
18
+ toLong: () => number;
19
+ toBigInt: () => bigint;
20
+ offset: (num: number) => Addr | null;
21
+ compare: (other: string | Addr) => number;
22
+ clone: () => Addr;
23
+ and: (input: string | Addr) => Addr;
24
+ or: (input: string | Addr) => Addr;
25
+ not: () => Addr;
26
+ }
27
+
28
+ export interface AddrRange {
29
+ contains: (input: string | Addr) => boolean;
30
+ first: () => Addr;
31
+ last: () => Addr;
32
+ }
33
+
34
+ export interface CIDR extends AddrRange {
35
+ broadcast: () => Addr;
36
+ compare: (other: string | CIDR) => number;
37
+ prefixLength: (format?: "auto" | "v4" | "v6") => number;
38
+ address: () => Addr;
39
+ toString: (opts?: ToStringOpts) => string;
40
+ }
41
+
42
+ export function compare(addr1: string | Addr, addr2: string | Addr): number;
43
+
44
+ export function compareCIDR(cidr1: string | CIDR, cidr2: string | CIDR): number;
45
+
46
+ export function createAddrRange(begin: string | Addr, end: string | Addr): AddrRange;
47
+
48
+ export function createCIDR(addr: string | Addr, len?: number): CIDR;
49
+
50
+ export function parse(input: string | number | Addr | BigInt): Addr;
51
+
52
+ }