geoip-lite2 2.2.6 → 2.2.7

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/README.md CHANGED
@@ -181,7 +181,7 @@ npm run updatedb-force license_key=YOUR_LICENSE_KEY
181
181
 
182
182
  You can also run it by doing:
183
183
  ```shell
184
- node ./node_modules/geoip-lite2/utils/updatedb.js license_key=YOUR_LICENSE_KEY
184
+ node ./node_modules/geoip-lite2/tools/updatedb.js license_key=YOUR_LICENSE_KEY
185
185
  ```
186
186
 
187
187
  ### Ways to reload data in your app when update finished
@@ -0,0 +1 @@
1
+ 9477be6926b39db95dcf6664e36bddd5900425ddb9952840ec5491d5c6ad6bdd GeoLite2-City-CSV_20250905.zip
@@ -0,0 +1 @@
1
+ 952a602f47c26afc46782e468b2464fcc7a6a44418bff3819a5d1e63481de5ec GeoLite2-Country-CSV_20250905.zip
@@ -0,0 +1 @@
1
+ const{access:e,constants:n,watch:t}=require('node:fs'),{join:o}=require('node:path'),l={},u=e=>l[e].close();module.exports={makeFsWatchFilter:(c,r,s,i,a)=>{let f=null;function h(){f=null,a()}'function'==typeof i&&(a=i,i=s,s=null),l[c]&&u(c),l[c]=t(r,function(t,l){if(!l)return;const u=o(r,l);s&&s!==l||e(u,n.F_OK,e=>{if(e)return console.error(e);null!==f&&(clearTimeout(f),f=null),f=setTimeout(h,i)})})},stopWatching:u};
package/dist/main.js ADDED
@@ -0,0 +1 @@
1
+ const{open:e,fstat:r,read:t,close:n,openSync:i,fstatSync:a,readSync:o,closeSync:l}=require('node:fs'),{join:u,resolve:c}=require('node:path'),{isIP:f}=require('node:net'),s=require('async'),{aton4:d,aton6:y,cmp6:B,ntoa4:S,ntoa6:p,cmp:g}=require('./utils.js'),I=require('./fsWatcher.js'),{version:E}=require('../package.json'),m='dataWatcher',z=c(__dirname,global.geoDataDir||process.env.GEODATADIR||'../data/'),N={city:u(z,'geoip-city.dat'),city6:u(z,'geoip-city6.dat'),cityNames:u(z,'geoip-city-names.dat'),country:u(z,'geoip-country.dat'),country6:u(z,'geoip-country6.dat')},P=[[d('10.0.0.0'),d('10.255.255.255')],[d('172.16.0.0'),d('172.31.255.255')],[d('192.168.0.0'),d('192.168.255.255')]],h={firstIP:null,lastIP:null,lastLine:0,locationBuffer:null,locationRecordSize:88,mainBuffer:null,recordSize:24},F={firstIP:null,lastIP:null,lastLine:0,mainBuffer:null,recordSize:48};let O=JSON.parse(JSON.stringify(h)),L=JSON.parse(JSON.stringify(F));const U=e=>{let r,t,n=0,i=O.lastLine,a=O.lastIP,o=O.firstIP;const l=O.mainBuffer,u=O.locationBuffer,c=P,f=O.recordSize,s=O.locationRecordSize,d={range:[null,null],country:'',region:'',eu:'',timezone:'',city:'',ll:[null,null],metro:null,area:null};if(e>O.lastIP||e<O.firstIP)return null;for(let r=0;r<c.length;r++)if(e>=c[r][0]&&e<=c[r][1])return null;for(;;){if(r=Math.round((i-n)/2)+n,a=l.readUInt32BE(r*f),o=l.readUInt32BE(r*f+4),a<=e&&o>=e)return d.range=[a,o],10===f?d.country=l.toString('utf8',r*f+8,r*f+10):(t=l.readUInt32BE(r*f+8),-1>>>0>t&&(d.country=u.toString('utf8',t*s,t*s+2).replace(/\u0000.*/,''),d.region=u.toString('utf8',t*s+2,t*s+5).replace(/\u0000.*/,''),d.metro=u.readInt32BE(t*s+5),d.ll[0]=l.readInt32BE(r*f+12)/1e4,d.ll[1]=l.readInt32BE(r*f+16)/1e4,d.area=l.readUInt32BE(r*f+20),d.eu=u.toString('utf8',t*s+9,t*s+10).replace(/\u0000.*/,''),d.timezone=u.toString('utf8',t*s+10,t*s+42).replace(/\u0000.*/,''),d.city=u.toString('utf8',t*s+42,t*s+s).replace(/\u0000.*/,''))),d;if(n===i)return null;n===i-1?r===n?n=i:i=n:a>e?i=r:o<e&&(n=r)}},D=['0:0:0:0:0:FFFF:','::FFFF:'];function J(u){let c,f;const d=JSON.parse(JSON.stringify(h));if('function'==typeof arguments[0])s.series([i=>{s.series([r=>{e(N.cityNames,'r',(e,t)=>{c=t,r(e)})},e=>{r(c,(r,t)=>{f=t.size,d.locationBuffer=Buffer.alloc(f),e(r)})},e=>{t(c,d.locationBuffer,0,f,0,e)},e=>{n(c,e)},r=>{e(N.city,'r',(e,t)=>{c=t,r(e)})},e=>{r(c,(r,t)=>{f=t.size,e(r)})}],t=>{if(t){if('ENOENT'!==t.code&&'EBADF'!==t.code)throw t;e(N.country,'r',(e,t)=>{e?i(e):(c=t,r(c,(e,r)=>{f=r.size,d.recordSize=10,i()}))})}else i()})},()=>{d.mainBuffer=Buffer.alloc(f),s.series([e=>{t(c,d.mainBuffer,0,f,0,e)},e=>{n(c,e)}],e=>{e||(d.lastLine=f/d.recordSize-1,d.lastIP=d.mainBuffer.readUInt32BE(d.lastLine*d.recordSize+4),d.firstIP=d.mainBuffer.readUInt32BE(0),O=d),u(e)})}]);else{try{if(c=i(N.cityNames,'r'),f=a(c).size,0===f)throw{code:'EMPTY_FILE'};O.locationBuffer=Buffer.alloc(f),o(c,O.locationBuffer,0,f,0),l(c),c=i(N.city,'r'),f=a(c).size}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;c=i(N.country,'r'),f=a(c).size,O.recordSize=10}O.mainBuffer=Buffer.alloc(f),o(c,O.mainBuffer,0,f,0),l(c),O.lastLine=f/O.recordSize-1,O.lastIP=O.mainBuffer.readUInt32BE(O.lastLine*O.recordSize+4),O.firstIP=O.mainBuffer.readUInt32BE(0)}}function T(u){let c,f;const d=JSON.parse(JSON.stringify(F));if('function'==typeof arguments[0])s.series([t=>{s.series([r=>{e(N.city6,'r',(e,t)=>{c=t,r(e)})},e=>{r(c,(r,t)=>{f=t.size,e(r)})}],n=>{if(n){if('ENOENT'!==n.code&&'EBADF'!==n.code)throw n;e(N.country6,'r',(e,n)=>{e?t(e):(c=n,r(c,(e,r)=>{f=r.size,d.recordSize=34,t()}))})}else t()})},()=>{d.mainBuffer=Buffer.alloc(f),s.series([e=>{t(c,d.mainBuffer,0,f,0,e)},e=>{n(c,e)}],e=>{e||(d.lastLine=f/d.recordSize-1,L=d),u(e)})}]);else{try{if(c=i(N.city6,'r'),f=a(c).size,0===f)throw{code:'EMPTY_FILE'}}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;c=i(N.country6,'r'),f=a(c).size,L.recordSize=34}L.mainBuffer=Buffer.alloc(f),o(c,L.mainBuffer,0,f,0),l(c),L.lastLine=f/L.recordSize-1}}module.exports={cmp:g,lookup:e=>{if(!e)return null;if('number'==typeof e)return U(e);if(4===f(e))return U(d(e));if(6===f(e)){const r=(e=>{const r=e.toUpperCase();for(let e=0;e<D.length;e++){const t=D[e];if(0===r.indexOf(t))return r.substring(t.length)}return null})(e);return r?U(d(r)):(e=>{const r=L.mainBuffer,t=L.recordSize,n=O.locationBuffer,i=O.locationRecordSize,a={range:[null,null],country:'',region:'',city:'',ll:[0,0],metro:null,area:null,eu:'',timezone:''},o=(e,n)=>{const i=[];for(let a=0;a<2;a++)i.push(r.readUInt32BE(e*t+16*n+4*a));return i};L.lastIP=o(L.lastLine,1),L.firstIP=o(0,0);let l,u,c=0,f=L.lastLine,s=L.lastIP,d=L.firstIP;if(B(e,L.lastIP)>0||B(e,L.firstIP)<0)return null;for(;;){if(l=Math.round((f-c)/2)+c,s=o(l,0),d=o(l,1),B(s,e)<=0&&B(d,e)>=0)return 34===t?a.country=r.toString('utf8',l*t+32,l*t+34).replace(/\u0000.*/,''):(u=r.readUInt32BE(l*t+32),-1>>>0>u&&(a.country=n.toString('utf8',u*i,u*i+2).replace(/\u0000.*/,''),a.region=n.toString('utf8',u*i+2,u*i+5).replace(/\u0000.*/,''),a.metro=n.readInt32BE(u*i+5),a.ll[0]=r.readInt32BE(l*t+36)/1e4,a.ll[1]=r.readInt32BE(l*t+40)/1e4,a.area=r.readUInt32BE(l*t+44),a.eu=n.toString('utf8',u*i+9,u*i+10).replace(/\u0000.*/,''),a.timezone=n.toString('utf8',u*i+10,u*i+42).replace(/\u0000.*/,''),a.city=n.toString('utf8',u*i+42,u*i+i).replace(/\u0000.*/,''))),a;if(c===f)return null;c===f-1?l===c?c=f:f=c:B(s,e)>0?f=l:B(d,e)<0&&(c=l)}})(y(e))}return null},pretty:e=>'string'==typeof e?e:'number'==typeof e?S(e):Array.isArray(e)?p(e):e,startWatchingDataUpdate:e=>{I.makeFsWatchFilter(m,z,6e4,async()=>{await s.series([e=>{J(e)},e=>{T(e)}],e)})},stopWatchingDataUpdate:()=>I.stopWatching(m),clear:()=>{O=JSON.parse(JSON.stringify(h)),L=JSON.parse(JSON.stringify(F))},reloadDataSync:()=>{J(),T()},reloadData:async e=>{await s.series([e=>{J(e)},e=>{T(e)}],e)},version:E},J(),T();
package/index.d.ts CHANGED
@@ -1,34 +1,20 @@
1
- declare module 'geoip-lite2' {
2
- export const cmp: number | null;
1
+ interface GeoIp2Location {
2
+ range: [number | null, number | null];
3
+ country: string;
4
+ region: string;
5
+ eu: '0' | '1';
6
+ timezone: string;
7
+ city: string;
8
+ ll: [number | null, number | null];
9
+ metro: number;
10
+ area: number;
11
+ }
3
12
 
4
- interface GeoIp2Location {
5
- range: [number | null, number | null];
6
- country: string;
7
- region: string;
8
- eu: '0' | '1';
9
- timezone: string;
10
- city: string;
11
- ll: [number | null, number | null];
12
- metro: number;
13
- area: number;
14
- }
15
-
16
- function lookup(ip: string | number): GeoIp2Location | null;
17
- function pretty(n: string | number | any[]): string;
18
-
19
- function reloadDataSync(): void;
20
- function reloadData(callback: (err?: Error | null) => void): Promise<void>;
21
- function startWatchingDataUpdate(callback: () => void): void;
22
- function stopWatchingDataUpdate(): void;
23
- function clear(): void;
24
-
25
- export {
26
- lookup,
27
- pretty,
28
- reloadDataSync,
29
- reloadData,
30
- startWatchingDataUpdate,
31
- stopWatchingDataUpdate,
32
- clear
33
- };
34
- }
13
+ export function lookup(ip: string | number): GeoIp2Location | null;
14
+ export function pretty(n: string | number | any[]): string;
15
+ export function reloadDataSync(): void;
16
+ export function reloadData(callback?: (err?: Error | null) => void): Promise<void>;
17
+ export function startWatchingDataUpdate(callback: () => void): void;
18
+ export function stopWatchingDataUpdate(): void;
19
+ export function clear(): void;
20
+ export const version: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "geoip-lite2",
3
- "version": "2.2.6",
3
+ "version": "2.2.7",
4
4
  "description": "A light weight native JavaScript implementation of GeoIP API from MaxMind. Improved and faster version by Sefinek.",
5
5
  "keywords": [
6
6
  "city",
@@ -52,32 +52,41 @@
52
52
  "license": "Apache-2.0",
53
53
  "author": "Philip Tellis <philip@bluesmoon.info> (https://bluesmoon.info)",
54
54
  "type": "commonjs",
55
- "main": "lib-minified/main.js",
55
+ "main": "dist/main.js",
56
56
  "types": "index.d.ts",
57
57
  "directories": {
58
58
  "lib": "lib",
59
59
  "test": "test"
60
60
  },
61
+ "files": [
62
+ "data",
63
+ "dist",
64
+ "tools",
65
+ "AUTHORS",
66
+ "index.d.ts",
67
+ "LICENSE",
68
+ "README.md"
69
+ ],
61
70
  "scripts": {
62
71
  "minify": "node minify.js",
63
72
  "test": "jest test",
64
73
  "up": "ncu -u && npm install && npm update && npm audit fix",
65
- "updatedb": "node utils-minified/updatedb.js",
66
- "updatedb-debug": "node utils-minified/updatedb.js debug",
67
- "updatedb-force": "node utils-minified/updatedb.js force"
74
+ "updatedb": "node tools/updatedb.js",
75
+ "updatedb-debug": "node tools/updatedb.js debug",
76
+ "updatedb-force": "node tools/updatedb.js force"
68
77
  },
69
78
  "dependencies": {
70
79
  "adm-zip": "^0.5.16",
71
80
  "async": "^3.2.6",
72
- "iconv-lite": "0.6.3",
81
+ "iconv-lite": "0.7.0",
73
82
  "ip-address": "^10.0.1",
74
83
  "rimraf": "^6.0.1"
75
84
  },
76
85
  "devDependencies": {
77
- "@eslint/js": "^9.29.0",
78
- "globals": "^16.2.0",
79
- "jest": "^30.0.2",
80
- "terser": "^5.43.1"
86
+ "@eslint/js": "^9.35.0",
87
+ "globals": "^16.3.0",
88
+ "jest": "^30.1.3",
89
+ "terser": "^5.44.0"
81
90
  },
82
91
  "engines": {
83
92
  "node": ">=10.3.0"
@@ -5,12 +5,12 @@
5
5
  const { name, version } = require('../package.json');
6
6
  const UserAgent = `Mozilla/5.0 (compatible; ${name}/${version}; +https://github.com/sefinek/geoip-lite2)`;
7
7
 
8
- const fs = require('fs');
9
- const http = require('http');
10
- const https = require('https');
11
- const path = require('path');
12
- const zlib = require('zlib');
13
- const readline = require('readline');
8
+ const fs = require('node:fs');
9
+ const http = require('node:http');
10
+ const https = require('node:https');
11
+ const path = require('node:path');
12
+ const zlib = require('node:zlib');
13
+ const readline = require('node:readline');
14
14
 
15
15
  const async = require('async');
16
16
  const { decodeStream } = require('iconv-lite');
@@ -30,7 +30,7 @@ if (typeof geoDataDir === 'undefined' && typeof process.env.GEODATADIR !== 'unde
30
30
  geoDataDir = `geoDataDir=${process.env.GEODATADIR}`;
31
31
  }
32
32
 
33
- let dataPath = path.resolve(__dirname, '..', 'geoip-data');
33
+ let dataPath = path.resolve(__dirname, '..', 'data');
34
34
  if (typeof geoDataDir !== 'undefined') {
35
35
  dataPath = path.resolve(process.cwd(), geoDataDir.split('=')[1]);
36
36
  if (!fs.existsSync(dataPath)) {
@@ -161,7 +161,6 @@ function check(database, cb) {
161
161
  if ([301, 302, 303, 307, 308].includes(status)) {
162
162
  return https.get(getHTTPOptions(response.headers.location), onResponse);
163
163
  } else if (status !== 200) {
164
- console.error(response.data);
165
164
  console.error('ERROR: HTTP Request Failed [%d %s]', status, http.STATUS_CODES[status]);
166
165
  client.end();
167
166
  process.exit(1);
@@ -1 +0,0 @@
1
- 7014a41dc60b27ef593d260eca0d4b396d38c924c0eee9859662f4ecae56b092 GeoLite2-City-CSV_20250620.zip
@@ -1 +0,0 @@
1
- 6c3d34a9eaa8d2bdafe85701f906c36c5f0eecde4f6c91a00499eaa612bfa26f GeoLite2-Country-CSV_20250620.zip
package/lib/fsWatcher.js DELETED
@@ -1,69 +0,0 @@
1
- const { access, constants, watch } = require('fs');
2
- const { join } = require('path');
3
- const FSWatcher = {};
4
-
5
- /**
6
- * Takes an FSWatcher object and closes it.
7
- * @param {string} name - The name of the watcher to close.
8
- */
9
- const stopWatching = name => FSWatcher[name].close();
10
-
11
- /**
12
- * Takes a directory/file and watch for change. Upon change, call the callback.
13
- *
14
- * @param {String} name - name of this watcher
15
- * @param {String} directory - path to the directory to watch
16
- * @param {String} [filename] - (optional) specific filename to watch for, watches for all files in the directory if unspecified
17
- * @param {Number} cdDelay - delay to wait before triggering the callback
18
- * @param {Function} callback - function() - called when changes are detected
19
- */
20
- const makeFsWatchFilter = (name, directory, filename, cdDelay, callback) => {
21
- let cdId = null;
22
-
23
- // Delete the cdId and callback the outer function
24
- function timeoutCallback() {
25
- cdId = null;
26
- callback();
27
- }
28
-
29
- // This function is called when there is a change in the data directory
30
- // It sets a timer to wait for the change to be completed
31
- function onWatchEvent(event, changedFile) {
32
- // Check to make sure changedFile is not null
33
- if (!changedFile) return;
34
-
35
- const filePath = join(directory, changedFile);
36
- if (!filename || filename === changedFile) {
37
- access(filePath, constants.F_OK, err => {
38
- if (err) return console.error(err);
39
-
40
- // At this point, a new file system activity has been detected,
41
- // We have to wait for file transfer to be finished before moving on.
42
-
43
- // If a cdId already exists, we delete it
44
- if (cdId !== null) {
45
- clearTimeout(cdId);
46
- cdId = null;
47
- }
48
-
49
- // Once the cdDelay has passed, the timeoutCallback function will be called
50
- cdId = setTimeout(timeoutCallback, cdDelay);
51
- });
52
- }
53
- }
54
-
55
- // Manage the case where filename is missing (because it's optional)
56
- if (typeof cdDelay === 'function') {
57
- callback = cdDelay;
58
- cdDelay = filename;
59
- filename = null;
60
- }
61
-
62
- if (FSWatcher[name]) {
63
- stopWatching(name);
64
- }
65
-
66
- FSWatcher[name] = watch(directory, onWatchEvent);
67
- };
68
-
69
- module.exports = { makeFsWatchFilter, stopWatching };
package/lib/main.js DELETED
@@ -1,501 +0,0 @@
1
- const { open, fstat, read, close, openSync, fstatSync, readSync, closeSync } = require('fs');
2
- const { join, resolve } = require('path');
3
- const { isIP } = require('net');
4
- const async = require('async');
5
- const { aton4, aton6, cmp6, ntoa4, ntoa6, cmp } = require('./utils.js');
6
- const fsWatcher = require('./fsWatcher.js');
7
- const { version } = require('../package.json');
8
-
9
- const watcherName = 'dataWatcher';
10
-
11
- const geoDataDir = resolve(
12
- __dirname,
13
- global.geoDataDir || process.env.GEODATADIR || '../geoip-data/'
14
- );
15
-
16
- const dataFiles = {
17
- city: join(geoDataDir, 'geoip-city.dat'),
18
- city6: join(geoDataDir, 'geoip-city6.dat'),
19
- cityNames: join(geoDataDir, 'geoip-city-names.dat'),
20
- country: join(geoDataDir, 'geoip-country.dat'),
21
- country6: join(geoDataDir, 'geoip-country6.dat'),
22
- };
23
-
24
- const privateRange4 = [
25
- [aton4('10.0.0.0'), aton4('10.255.255.255')],
26
- [aton4('172.16.0.0'), aton4('172.31.255.255')],
27
- [aton4('192.168.0.0'), aton4('192.168.255.255')],
28
- ];
29
-
30
- const conf4 = {
31
- firstIP: null,
32
- lastIP: null,
33
- lastLine: 0,
34
- locationBuffer: null,
35
- locationRecordSize: 88,
36
- mainBuffer: null,
37
- recordSize: 24,
38
- };
39
-
40
- const conf6 = {
41
- firstIP: null,
42
- lastIP: null,
43
- lastLine: 0,
44
- mainBuffer: null,
45
- recordSize: 48,
46
- };
47
-
48
- // Copy original configs
49
- let cache4 = JSON.parse(JSON.stringify(conf4));
50
- let cache6 = JSON.parse(JSON.stringify(conf6));
51
-
52
- const RECORD_SIZE = 10;
53
- const RECORD_SIZE6 = 34;
54
-
55
- const lookup4 = ip => {
56
- let fline = 0;
57
- let cline = cache4.lastLine;
58
- let floor = cache4.lastIP;
59
- let ceil = cache4.firstIP;
60
- let line, locId;
61
-
62
- const buffer = cache4.mainBuffer;
63
- const locBuffer = cache4.locationBuffer;
64
- const privateRange = privateRange4;
65
- const recordSize = cache4.recordSize;
66
- const locRecordSize = cache4.locationRecordSize;
67
-
68
- const geoData = {
69
- range: [null, null],
70
- country: '',
71
- region: '',
72
- eu: '',
73
- timezone: '',
74
- city: '',
75
- ll: [null, null],
76
- metro: null,
77
- area: null,
78
- };
79
-
80
- // Outside IPv4 range
81
- if (ip > cache4.lastIP || ip < cache4.firstIP) return null;
82
-
83
- // Private IP
84
- for (let i = 0; i < privateRange.length; i++) {
85
- if (ip >= privateRange[i][0] && ip <= privateRange[i][1]) return null;
86
- }
87
-
88
- while (true) {
89
- line = Math.round((cline - fline) / 2) + fline;
90
- floor = buffer.readUInt32BE(line * recordSize);
91
- ceil = buffer.readUInt32BE((line * recordSize) + 4);
92
-
93
- if (floor <= ip && ceil >= ip) {
94
- geoData.range = [floor, ceil];
95
-
96
- if (recordSize === RECORD_SIZE) {
97
- geoData.country = buffer.toString('utf8', (line * recordSize) + 8, (line * recordSize) + 10);
98
- } else {
99
- locId = buffer.readUInt32BE((line * recordSize) + 8);
100
-
101
- // -1>>>0 is a marker for "No Location Info"
102
- if (-1 >>> 0 > locId) {
103
- geoData.country = locBuffer.toString('utf8', (locId * locRecordSize), (locId * locRecordSize) + 2).replace(/\u0000.*/, '');
104
- geoData.region = locBuffer.toString('utf8', (locId * locRecordSize) + 2, (locId * locRecordSize) + 5).replace(/\u0000.*/, '');
105
- geoData.metro = locBuffer.readInt32BE((locId * locRecordSize) + 5);
106
- geoData.ll[0] = buffer.readInt32BE((line * recordSize) + 12) / 10000; // latitude
107
- geoData.ll[1] = buffer.readInt32BE((line * recordSize) + 16) / 10000; // longitude
108
- geoData.area = buffer.readUInt32BE((line * recordSize) + 20);
109
- geoData.eu = locBuffer.toString('utf8', (locId * locRecordSize) + 9, (locId * locRecordSize) + 10).replace(/\u0000.*/, '');
110
- geoData.timezone = locBuffer.toString('utf8', (locId * locRecordSize) + 10, (locId * locRecordSize) + 42).replace(/\u0000.*/, '');
111
- geoData.city = locBuffer.toString('utf8', (locId * locRecordSize) + 42, (locId * locRecordSize) + locRecordSize).replace(/\u0000.*/, '');
112
- }
113
- }
114
-
115
- return geoData;
116
- } else if (fline === cline) {
117
- return null;
118
- } else if (fline === (cline - 1)) {
119
- if (line === fline) {
120
- fline = cline;
121
- } else {
122
- cline = fline;
123
- }
124
- } else if (floor > ip) {
125
- cline = line;
126
- } else if (ceil < ip) {
127
- fline = line;
128
- }
129
- }
130
- };
131
-
132
- const lookup6 = ip => {
133
- const buffer = cache6.mainBuffer;
134
- const recordSize = cache6.recordSize;
135
- const locBuffer = cache4.locationBuffer;
136
- const locRecordSize = cache4.locationRecordSize;
137
-
138
- const geoData = { range: [null, null], country: '', region: '', city: '', ll: [0, 0], metro: null, area: null, eu: '', timezone: '' };
139
-
140
- const readIp = (line, offset) => {
141
- const ipArray = [];
142
- for (let i = 0; i < 2; i++) {
143
- ipArray.push(buffer.readUInt32BE((line * recordSize) + (offset * 16) + (i * 4)));
144
- }
145
- return ipArray;
146
- };
147
-
148
- cache6.lastIP = readIp(cache6.lastLine, 1);
149
- cache6.firstIP = readIp(0, 0);
150
-
151
- let fline = 0;
152
- let cline = cache6.lastLine;
153
- let floor = cache6.lastIP;
154
- let ceil = cache6.firstIP;
155
- let line, locId;
156
-
157
- if (cmp6(ip, cache6.lastIP) > 0 || cmp6(ip, cache6.firstIP) < 0) return null;
158
-
159
- while (true) {
160
- line = Math.round((cline - fline) / 2) + fline;
161
- floor = readIp(line, 0);
162
- ceil = readIp(line, 1);
163
-
164
- if (cmp6(floor, ip) <= 0 && cmp6(ceil, ip) >= 0) {
165
- if (recordSize === RECORD_SIZE6) {
166
- geoData.country = buffer.toString('utf8', (line * recordSize) + 32, (line * recordSize) + 34).replace(/\u0000.*/, '');
167
- } else {
168
- locId = buffer.readUInt32BE((line * recordSize) + 32);
169
-
170
- // -1>>>0 is a marker for "No Location Info"
171
- if (-1 >>> 0 > locId) {
172
- geoData.country = locBuffer.toString('utf8', (locId * locRecordSize), (locId * locRecordSize) + 2).replace(/\u0000.*/, '');
173
- geoData.region = locBuffer.toString('utf8', (locId * locRecordSize) + 2, (locId * locRecordSize) + 5).replace(/\u0000.*/, '');
174
- geoData.metro = locBuffer.readInt32BE((locId * locRecordSize) + 5);
175
- geoData.ll[0] = buffer.readInt32BE((line * recordSize) + 36) / 10000; // latitude
176
- geoData.ll[1] = buffer.readInt32BE((line * recordSize) + 40) / 10000; // longitude
177
- geoData.area = buffer.readUInt32BE((line * recordSize) + 44); // area
178
- geoData.eu = locBuffer.toString('utf8', (locId * locRecordSize) + 9, (locId * locRecordSize) + 10).replace(/\u0000.*/, '');
179
- geoData.timezone = locBuffer.toString('utf8', (locId * locRecordSize) + 10, (locId * locRecordSize) + 42).replace(/\u0000.*/, '');
180
- geoData.city = locBuffer.toString('utf8', (locId * locRecordSize) + 42, (locId * locRecordSize) + locRecordSize).replace(/\u0000.*/, '');
181
- }
182
- }
183
- // We do not currently have detailed region/city info for IPv6, but finally have coords
184
- return geoData;
185
- } else if (fline === cline) {
186
- return null;
187
- } else if (fline === (cline - 1)) {
188
- if (line === fline) {
189
- fline = cline;
190
- } else {
191
- cline = fline;
192
- }
193
- } else if (cmp6(floor, ip) > 0) {
194
- cline = line;
195
- } else if (cmp6(ceil, ip) < 0) {
196
- fline = line;
197
- }
198
- }
199
- };
200
-
201
- const v6prefixes = ['0:0:0:0:0:FFFF:', '::FFFF:'];
202
- const get4mapped = ip => {
203
- const ipv6 = ip.toUpperCase();
204
- for (let i = 0; i < v6prefixes.length; i++) {
205
- const v6prefix = v6prefixes[i];
206
- if (ipv6.indexOf(v6prefix) === 0) return ipv6.substring(v6prefix.length);
207
- }
208
- return null;
209
- };
210
-
211
- function preload(callback) {
212
- let datFile;
213
- let datSize;
214
- const asyncCache = JSON.parse(JSON.stringify(conf4));
215
-
216
- // When the preload function receives a callback, do the task asynchronously
217
- if (typeof arguments[0] === 'function') {
218
- async.series([
219
- cb => {
220
- async.series([
221
- cb2 => {
222
- open(dataFiles.cityNames, 'r', (err, file) => {
223
- datFile = file;
224
- cb2(err);
225
- });
226
- },
227
- cb2 => {
228
- fstat(datFile, (err, stats) => {
229
- datSize = stats.size;
230
- asyncCache.locationBuffer = Buffer.alloc(datSize);
231
- cb2(err);
232
- });
233
- },
234
- cb2 => {
235
- read(datFile, asyncCache.locationBuffer, 0, datSize, 0, cb2);
236
- },
237
- cb2 => {
238
- close(datFile, cb2);
239
- },
240
- cb2 => {
241
- open(dataFiles.city, 'r', (err, file) => {
242
- datFile = file;
243
- cb2(err);
244
- });
245
- },
246
- cb2 => {
247
- fstat(datFile, (err, stats) => {
248
- datSize = stats.size;
249
- cb2(err);
250
- });
251
- },
252
- ], err => {
253
- if (err) {
254
- if (err.code !== 'ENOENT' && err.code !== 'EBADF') {
255
- throw err;
256
- }
257
-
258
- open(dataFiles.country, 'r', (err, file) => {
259
- if (err) {
260
- cb(err);
261
- } else {
262
- datFile = file;
263
- fstat(datFile, (err, stats) => {
264
- datSize = stats.size;
265
- asyncCache.recordSize = RECORD_SIZE;
266
-
267
- cb();
268
- });
269
- }
270
- });
271
-
272
- } else {
273
- cb();
274
- }
275
- });
276
- }, () => {
277
- asyncCache.mainBuffer = Buffer.alloc(datSize);
278
-
279
- async.series([
280
- cb2 => {
281
- read(datFile, asyncCache.mainBuffer, 0, datSize, 0, cb2);
282
- },
283
- cb2 => {
284
- close(datFile, cb2);
285
- },
286
- ], err => {
287
- if (!err) {
288
- asyncCache.lastLine = (datSize / asyncCache.recordSize) - 1;
289
- asyncCache.lastIP = asyncCache.mainBuffer.readUInt32BE((asyncCache.lastLine * asyncCache.recordSize) + 4);
290
- asyncCache.firstIP = asyncCache.mainBuffer.readUInt32BE(0);
291
- cache4 = asyncCache;
292
- }
293
- callback(err);
294
- });
295
- },
296
- ]);
297
- } else {
298
- try {
299
- datFile = openSync(dataFiles.cityNames, 'r');
300
- datSize = fstatSync(datFile).size;
301
- if (datSize === 0) throw { code: 'EMPTY_FILE' };
302
-
303
- cache4.locationBuffer = Buffer.alloc(datSize);
304
- readSync(datFile, cache4.locationBuffer, 0, datSize, 0);
305
- closeSync(datFile);
306
-
307
- datFile = openSync(dataFiles.city, 'r');
308
- datSize = fstatSync(datFile).size;
309
- } catch (err) {
310
- if (err.code !== 'ENOENT' && err.code !== 'EBADF' && err.code !== 'EMPTY_FILE') {
311
- throw err;
312
- }
313
-
314
- datFile = openSync(dataFiles.country, 'r');
315
- datSize = fstatSync(datFile).size;
316
- cache4.recordSize = RECORD_SIZE;
317
- }
318
-
319
- cache4.mainBuffer = Buffer.alloc(datSize);
320
- readSync(datFile, cache4.mainBuffer, 0, datSize, 0);
321
- closeSync(datFile);
322
-
323
- cache4.lastLine = (datSize / cache4.recordSize) - 1;
324
- cache4.lastIP = cache4.mainBuffer.readUInt32BE((cache4.lastLine * cache4.recordSize) + 4);
325
- cache4.firstIP = cache4.mainBuffer.readUInt32BE(0);
326
- }
327
- }
328
-
329
- function preload6(callback) {
330
- let datFile;
331
- let datSize;
332
- const asyncCache6 = JSON.parse(JSON.stringify(conf6));
333
-
334
- // When the preload function receives a callback, do the task asynchronously
335
- if (typeof arguments[0] === 'function') {
336
- async.series([
337
- cb => {
338
- async.series([
339
- cb2 => {
340
- open(dataFiles.city6, 'r', (err, file) => {
341
- datFile = file;
342
- cb2(err);
343
- });
344
- },
345
- cb2 => {
346
- fstat(datFile, (err, stats) => {
347
- datSize = stats.size;
348
- cb2(err);
349
- });
350
- },
351
- ], err => {
352
- if (err) {
353
- if (err.code !== 'ENOENT' && err.code !== 'EBADF') {
354
- throw err;
355
- }
356
-
357
- open(dataFiles.country6, 'r', (err, file) => {
358
- if (err) {
359
- cb(err);
360
- } else {
361
- datFile = file;
362
- fstat(datFile, (err, stats) => {
363
- datSize = stats.size;
364
- asyncCache6.recordSize = RECORD_SIZE6;
365
-
366
- cb();
367
- });
368
- }
369
- });
370
- } else {
371
- cb();
372
- }
373
- });
374
- }, () => {
375
- asyncCache6.mainBuffer = Buffer.alloc(datSize);
376
-
377
- async.series([
378
- cb2 => {
379
- read(datFile, asyncCache6.mainBuffer, 0, datSize, 0, cb2);
380
- },
381
- cb2 => {
382
- close(datFile, cb2);
383
- },
384
- ], err => {
385
- if (!err) {
386
- asyncCache6.lastLine = (datSize / asyncCache6.recordSize) - 1;
387
- cache6 = asyncCache6;
388
- }
389
- callback(err);
390
- });
391
- },
392
- ]);
393
- } else {
394
- try {
395
- datFile = openSync(dataFiles.city6, 'r');
396
- datSize = fstatSync(datFile).size;
397
-
398
- if (datSize === 0) throw { code: 'EMPTY_FILE' };
399
- } catch (err) {
400
- if (err.code !== 'ENOENT' && err.code !== 'EBADF' && err.code !== 'EMPTY_FILE') {
401
- throw err;
402
- }
403
-
404
- datFile = openSync(dataFiles.country6, 'r');
405
- datSize = fstatSync(datFile).size;
406
- cache6.recordSize = RECORD_SIZE6;
407
- }
408
-
409
- cache6.mainBuffer = Buffer.alloc(datSize);
410
- readSync(datFile, cache6.mainBuffer, 0, datSize, 0);
411
- closeSync(datFile);
412
-
413
- cache6.lastLine = (datSize / cache6.recordSize) - 1;
414
- }
415
- }
416
-
417
- module.exports = {
418
- cmp,
419
-
420
- lookup: ip => {
421
- if (!ip) {
422
- return null;
423
- } else if (typeof ip === 'number') {
424
- return lookup4(ip);
425
- } else if (isIP(ip) === 4) {
426
- return lookup4(aton4(ip));
427
- } else if (isIP(ip) === 6) {
428
- const ipv4 = get4mapped(ip);
429
- if (ipv4) {
430
- return lookup4(aton4(ipv4));
431
- } else {
432
- return lookup6(aton6(ip));
433
- }
434
- }
435
-
436
- return null;
437
- },
438
-
439
- pretty: n => {
440
- if (typeof n === 'string') {
441
- return n;
442
- } else if (typeof n === 'number') {
443
- return ntoa4(n);
444
- } else if (Array.isArray(n)) {
445
- return ntoa6(n);
446
- }
447
-
448
- return n;
449
- },
450
-
451
- // Start watching for data updates. The watcher waits one minute for file transfer to
452
- // complete before triggering the callback.
453
- startWatchingDataUpdate: callback => {
454
- fsWatcher.makeFsWatchFilter(watcherName, geoDataDir, 60 * 1000, async () => {
455
- // Reload data
456
- await async.series([
457
- cb => {
458
- preload(cb);
459
- }, cb => {
460
- preload6(cb);
461
- },
462
- ], callback);
463
- });
464
- },
465
-
466
- // Stop watching for data updates.
467
- stopWatchingDataUpdate: () => fsWatcher.stopWatching(watcherName),
468
-
469
- // Clear data
470
- clear: () => {
471
- cache4 = JSON.parse(JSON.stringify(conf4));
472
- cache6 = JSON.parse(JSON.stringify(conf6));
473
- },
474
-
475
- // Reload data synchronously
476
- reloadDataSync: () => {
477
- preload();
478
- preload6();
479
- },
480
-
481
- // Reload data asynchronously
482
- reloadData: async callback => {
483
- // Reload data
484
- await async.series([
485
- cb => {
486
- preload(cb);
487
- },
488
- cb => {
489
- preload6(cb);
490
- },
491
- ], callback);
492
- },
493
-
494
- version,
495
- };
496
-
497
- preload();
498
- preload6();
499
-
500
- // lookup4 = gen_lookup('geoip-country.dat', 4);
501
- // lookup6 = gen_lookup('geoip-country6.dat', 16);
package/lib/utils.js DELETED
@@ -1,86 +0,0 @@
1
- const utils = module.exports = {};
2
-
3
- utils.aton4 = a => {
4
- a = a.split(/\./);
5
- return ((parseInt(a[0], 10) << 24) >>> 0) + ((parseInt(a[1], 10) << 16) >>> 0) + ((parseInt(a[2], 10) << 8) >>> 0) + (parseInt(a[3], 10) >>> 0);
6
- };
7
-
8
- utils.aton6 = a => {
9
- a = a.replace(/"/g, '').split(/:/);
10
-
11
- const l = a.length - 1;
12
- let i;
13
-
14
- if (a[l] === '') {
15
- a[l] = 0;
16
- }
17
-
18
- if (l < 7) {
19
- a.length = 8;
20
-
21
- for (i = l; i >= 0 && a[i] !== ''; i--) {
22
- a[7 - l + i] = a[i];
23
- }
24
- }
25
-
26
- for (i = 0; i < 8; i++) {
27
- if (!a[i]) {
28
- a[i] = 0;
29
- } else {
30
- a[i] = parseInt(a[i], 16);
31
- }
32
- }
33
-
34
- const r = [];
35
- for (i = 0; i < 4; i++) {
36
- r.push(((a[2 * i] << 16) + a[2 * i + 1]) >>> 0);
37
- }
38
-
39
- return r;
40
- };
41
-
42
-
43
- utils.cmp = (a, b) => {
44
- if (typeof a === 'number' && typeof b === 'number') return (a < b ? -1 : (a > b ? 1 : 0));
45
- if (a instanceof Array && b instanceof Array) return this.cmp6(a, b);
46
-
47
- return null;
48
- };
49
-
50
- utils.cmp6 = (a, b) => {
51
- for (let ii = 0; ii < 2; ii++) {
52
- if (a[ii] < b[ii]) return -1;
53
- if (a[ii] > b[ii]) return 1;
54
- }
55
-
56
- return 0;
57
- };
58
-
59
- utils.isPrivateIP = addr => {
60
- addr = addr.toString();
61
-
62
- return addr.match(/^10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/) != null ||
63
- addr.match(/^192\.168\.([0-9]{1,3})\.([0-9]{1,3})/) != null ||
64
- addr.match(/^172\.16\.([0-9]{1,3})\.([0-9]{1,3})/) != null ||
65
- addr.match(/^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/) != null ||
66
- addr.match(/^169\.254\.([0-9]{1,3})\.([0-9]{1,3})/) != null ||
67
- addr.match(/^fc00:/) != null || addr.match(/^fe80:/) != null;
68
- };
69
-
70
- utils.ntoa4 = n => {
71
- n = n.toString();
72
- n = '' + (n >>> 24 & 0xff) + '.' + (n >>> 16 & 0xff) + '.' + (n >>> 8 & 0xff) + '.' + (n & 0xff);
73
- return n;
74
- };
75
-
76
- utils.ntoa6 = n => {
77
- let a = '[';
78
-
79
- for (let i = 0; i < n.length; i++) {
80
- a += (n[i] >>> 16).toString(16) + ':';
81
- a += (n[i] & 0xffff).toString(16) + ':';
82
- }
83
-
84
- a = a.replace(/:$/, ']').replace(/:0+/g, ':').replace(/::+/, '::');
85
- return a;
86
- };
@@ -1 +0,0 @@
1
- const{access:t,constants:e,watch:n}=require('fs'),{join:o}=require('path'),l={},u=t=>l[t].close();module.exports={makeFsWatchFilter:(c,r,s,i,a)=>{let f=null;function h(){f=null,a()}'function'==typeof i&&(a=i,i=s,s=null),l[c]&&u(c),l[c]=n(r,function(n,l){if(!l)return;const u=o(r,l);s&&s!==l||t(u,e.F_OK,t=>{if(t)return console.error(t);null!==f&&(clearTimeout(f),f=null),f=setTimeout(h,i)})})},stopWatching:u};
@@ -1 +0,0 @@
1
- const{open:e,fstat:r,read:t,close:n,openSync:i,fstatSync:a,readSync:o,closeSync:l}=require('fs'),{join:u,resolve:c}=require('path'),{isIP:f}=require('net'),s=require('async'),{aton4:d,aton6:y,cmp6:B,ntoa4:p,ntoa6:S,cmp:g}=require('./utils.js'),I=require('./fsWatcher.js'),{version:E}=require('../package.json'),m='dataWatcher',z=c(__dirname,global.geoDataDir||process.env.GEODATADIR||'../geoip-data/'),N={city:u(z,'geoip-city.dat'),city6:u(z,'geoip-city6.dat'),cityNames:u(z,'geoip-city-names.dat'),country:u(z,'geoip-country.dat'),country6:u(z,'geoip-country6.dat')},P=[[d('10.0.0.0'),d('10.255.255.255')],[d('172.16.0.0'),d('172.31.255.255')],[d('192.168.0.0'),d('192.168.255.255')]],h={firstIP:null,lastIP:null,lastLine:0,locationBuffer:null,locationRecordSize:88,mainBuffer:null,recordSize:24},F={firstIP:null,lastIP:null,lastLine:0,mainBuffer:null,recordSize:48};let O=JSON.parse(JSON.stringify(h)),L=JSON.parse(JSON.stringify(F));const U=e=>{let r,t,n=0,i=O.lastLine,a=O.lastIP,o=O.firstIP;const l=O.mainBuffer,u=O.locationBuffer,c=P,f=O.recordSize,s=O.locationRecordSize,d={range:[null,null],country:'',region:'',eu:'',timezone:'',city:'',ll:[null,null],metro:null,area:null};if(e>O.lastIP||e<O.firstIP)return null;for(let r=0;r<c.length;r++)if(e>=c[r][0]&&e<=c[r][1])return null;for(;;){if(r=Math.round((i-n)/2)+n,a=l.readUInt32BE(r*f),o=l.readUInt32BE(r*f+4),a<=e&&o>=e)return d.range=[a,o],10===f?d.country=l.toString('utf8',r*f+8,r*f+10):(t=l.readUInt32BE(r*f+8),-1>>>0>t&&(d.country=u.toString('utf8',t*s,t*s+2).replace(/\u0000.*/,''),d.region=u.toString('utf8',t*s+2,t*s+5).replace(/\u0000.*/,''),d.metro=u.readInt32BE(t*s+5),d.ll[0]=l.readInt32BE(r*f+12)/1e4,d.ll[1]=l.readInt32BE(r*f+16)/1e4,d.area=l.readUInt32BE(r*f+20),d.eu=u.toString('utf8',t*s+9,t*s+10).replace(/\u0000.*/,''),d.timezone=u.toString('utf8',t*s+10,t*s+42).replace(/\u0000.*/,''),d.city=u.toString('utf8',t*s+42,t*s+s).replace(/\u0000.*/,''))),d;if(n===i)return null;n===i-1?r===n?n=i:i=n:a>e?i=r:o<e&&(n=r)}},D=['0:0:0:0:0:FFFF:','::FFFF:'];function J(u){let c,f;const d=JSON.parse(JSON.stringify(h));if('function'==typeof arguments[0])s.series([i=>{s.series([r=>{e(N.cityNames,'r',(e,t)=>{c=t,r(e)})},e=>{r(c,(r,t)=>{f=t.size,d.locationBuffer=Buffer.alloc(f),e(r)})},e=>{t(c,d.locationBuffer,0,f,0,e)},e=>{n(c,e)},r=>{e(N.city,'r',(e,t)=>{c=t,r(e)})},e=>{r(c,(r,t)=>{f=t.size,e(r)})}],t=>{if(t){if('ENOENT'!==t.code&&'EBADF'!==t.code)throw t;e(N.country,'r',(e,t)=>{e?i(e):(c=t,r(c,(e,r)=>{f=r.size,d.recordSize=10,i()}))})}else i()})},()=>{d.mainBuffer=Buffer.alloc(f),s.series([e=>{t(c,d.mainBuffer,0,f,0,e)},e=>{n(c,e)}],e=>{e||(d.lastLine=f/d.recordSize-1,d.lastIP=d.mainBuffer.readUInt32BE(d.lastLine*d.recordSize+4),d.firstIP=d.mainBuffer.readUInt32BE(0),O=d),u(e)})}]);else{try{if(c=i(N.cityNames,'r'),f=a(c).size,0===f)throw{code:'EMPTY_FILE'};O.locationBuffer=Buffer.alloc(f),o(c,O.locationBuffer,0,f,0),l(c),c=i(N.city,'r'),f=a(c).size}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;c=i(N.country,'r'),f=a(c).size,O.recordSize=10}O.mainBuffer=Buffer.alloc(f),o(c,O.mainBuffer,0,f,0),l(c),O.lastLine=f/O.recordSize-1,O.lastIP=O.mainBuffer.readUInt32BE(O.lastLine*O.recordSize+4),O.firstIP=O.mainBuffer.readUInt32BE(0)}}function T(u){let c,f;const d=JSON.parse(JSON.stringify(F));if('function'==typeof arguments[0])s.series([t=>{s.series([r=>{e(N.city6,'r',(e,t)=>{c=t,r(e)})},e=>{r(c,(r,t)=>{f=t.size,e(r)})}],n=>{if(n){if('ENOENT'!==n.code&&'EBADF'!==n.code)throw n;e(N.country6,'r',(e,n)=>{e?t(e):(c=n,r(c,(e,r)=>{f=r.size,d.recordSize=34,t()}))})}else t()})},()=>{d.mainBuffer=Buffer.alloc(f),s.series([e=>{t(c,d.mainBuffer,0,f,0,e)},e=>{n(c,e)}],e=>{e||(d.lastLine=f/d.recordSize-1,L=d),u(e)})}]);else{try{if(c=i(N.city6,'r'),f=a(c).size,0===f)throw{code:'EMPTY_FILE'}}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;c=i(N.country6,'r'),f=a(c).size,L.recordSize=34}L.mainBuffer=Buffer.alloc(f),o(c,L.mainBuffer,0,f,0),l(c),L.lastLine=f/L.recordSize-1}}module.exports={cmp:g,lookup:e=>{if(!e)return null;if('number'==typeof e)return U(e);if(4===f(e))return U(d(e));if(6===f(e)){const r=(e=>{const r=e.toUpperCase();for(let e=0;e<D.length;e++){const t=D[e];if(0===r.indexOf(t))return r.substring(t.length)}return null})(e);return r?U(d(r)):(e=>{const r=L.mainBuffer,t=L.recordSize,n=O.locationBuffer,i=O.locationRecordSize,a={range:[null,null],country:'',region:'',city:'',ll:[0,0],metro:null,area:null,eu:'',timezone:''},o=(e,n)=>{const i=[];for(let a=0;a<2;a++)i.push(r.readUInt32BE(e*t+16*n+4*a));return i};L.lastIP=o(L.lastLine,1),L.firstIP=o(0,0);let l,u,c=0,f=L.lastLine,s=L.lastIP,d=L.firstIP;if(B(e,L.lastIP)>0||B(e,L.firstIP)<0)return null;for(;;){if(l=Math.round((f-c)/2)+c,s=o(l,0),d=o(l,1),B(s,e)<=0&&B(d,e)>=0)return 34===t?a.country=r.toString('utf8',l*t+32,l*t+34).replace(/\u0000.*/,''):(u=r.readUInt32BE(l*t+32),-1>>>0>u&&(a.country=n.toString('utf8',u*i,u*i+2).replace(/\u0000.*/,''),a.region=n.toString('utf8',u*i+2,u*i+5).replace(/\u0000.*/,''),a.metro=n.readInt32BE(u*i+5),a.ll[0]=r.readInt32BE(l*t+36)/1e4,a.ll[1]=r.readInt32BE(l*t+40)/1e4,a.area=r.readUInt32BE(l*t+44),a.eu=n.toString('utf8',u*i+9,u*i+10).replace(/\u0000.*/,''),a.timezone=n.toString('utf8',u*i+10,u*i+42).replace(/\u0000.*/,''),a.city=n.toString('utf8',u*i+42,u*i+i).replace(/\u0000.*/,''))),a;if(c===f)return null;c===f-1?l===c?c=f:f=c:B(s,e)>0?f=l:B(d,e)<0&&(c=l)}})(y(e))}return null},pretty:e=>'string'==typeof e?e:'number'==typeof e?p(e):Array.isArray(e)?S(e):e,startWatchingDataUpdate:e=>{I.makeFsWatchFilter(m,z,6e4,async()=>{await s.series([e=>{J(e)},e=>{T(e)}],e)})},stopWatchingDataUpdate:()=>I.stopWatching(m),clear:()=>{O=JSON.parse(JSON.stringify(h)),L=JSON.parse(JSON.stringify(F))},reloadDataSync:()=>{J(),T()},reloadData:async e=>{await s.series([e=>{J(e)},e=>{T(e)}],e)},version:E},J(),T();
package/minify.js DELETED
@@ -1,55 +0,0 @@
1
- const terser = require('terser');
2
- const fs = require('node:fs/promises');
3
- const path = require('node:path');
4
-
5
- const minifyJSFiles = async (sourceDirectory, outputDirectory) => {
6
- try {
7
- await fs.access(sourceDirectory);
8
- } catch {
9
- throw new Error(`Source directory does not exist: ${sourceDirectory}`);
10
- }
11
-
12
- await fs.rm(outputDirectory, { recursive: true, force: true });
13
- await fs.mkdir(outputDirectory, { recursive: true });
14
-
15
- const files = (await fs.readdir(sourceDirectory)).filter(file => file.endsWith('.js'));
16
- for (const file of files) {
17
- try {
18
- const code = await fs.readFile(path.join(sourceDirectory, file), 'utf8');
19
- const result = await terser.minify(code, {
20
- mangle: true,
21
- ecma: 2024,
22
- module: true,
23
- compress: {
24
- passes: 3,
25
- pure_funcs: ['console.info', 'console.debug'],
26
- hoist_funs: false,
27
- hoist_vars: true,
28
- reduce_funcs: true,
29
- reduce_vars: true,
30
- unsafe: false,
31
- unused: true,
32
- dead_code: true,
33
- },
34
- format: {
35
- quote_style: 3,
36
- preserve_annotations: true,
37
- comments: false,
38
- },
39
- toplevel: true,
40
- });
41
-
42
- await fs.writeFile(path.join(outputDirectory, file), result.code, 'utf8');
43
- console.log('Minimized:', file);
44
- } catch (err) {
45
- console.error(`Error processing ${file}:`, err.message);
46
- }
47
- }
48
-
49
- console.log('COMPLETED:', sourceDirectory);
50
- };
51
-
52
- (async () => {
53
- await minifyJSFiles('./lib', './lib-minified');
54
- await minifyJSFiles('./utils', './utils-minified');
55
- })();
package/test/example.js DELETED
@@ -1,7 +0,0 @@
1
- const geoIp2 = require('../lib/main.js');
2
-
3
- const ipv4 = geoIp2.lookup('109.199.64.0');
4
- console.log(ipv4);
5
-
6
- const ipv6 = geoIp2.lookup('2001:470:1:c84::111');
7
- console.log(ipv6);
@@ -1,55 +0,0 @@
1
- const assert = require('assert');
2
- const t1 = +new Date();
3
- const geoIp2 = require('../lib/main.js');
4
- const t2 = +new Date();
5
-
6
- if (process.argv.length > 2) {
7
- console.dir(geoIp2.lookup(process.argv[2]));
8
- const t3 = +new Date();
9
- console.log('Startup: %dms, exec: %dms', t2 - t1, t3 - t2);
10
- process.exit(1);
11
- }
12
-
13
- const f = [];
14
- let ip;
15
- const n = 30000;
16
- const nf = [];
17
- let r;
18
- const ts = +new Date();
19
-
20
- for (let i = 0; i < n; i++) {
21
- if ((i % 2) === 0) {
22
- ip = Math.round((Math.random() * 0xff000000) + 0xffffff);
23
- } else {
24
- ip = '2001:' +
25
- Math.round(Math.random() * 0xffff).toString(16) + ':' +
26
- Math.round(Math.random() * 0xffff).toString(16) + ':' +
27
- Math.round(Math.random() * 0xffff).toString(16) + ':' +
28
- Math.round(Math.random() * 0xffff).toString(16) + ':' +
29
- Math.round(Math.random() * 0xffff).toString(16) + ':' +
30
- Math.round(Math.random() * 0xffff).toString(16) + ':' +
31
- Math.round(Math.random() * 0xffff).toString(16) + '';
32
- }
33
-
34
- r = geoIp2.lookup(ip);
35
- if (r === null) {
36
- nf.push(ip);
37
- continue;
38
- }
39
-
40
- f.push([ip, r]);
41
-
42
- assert.ok(geoIp2.cmp(ip, r.range[0]) >= 0, 'Problem with ' + geoIp2.pretty(ip) + ' < ' + geoIp2.pretty(r.range[0]));
43
- assert.ok(geoIp2.cmp(ip, r.range[1]) <= 0, 'Problem with ' + geoIp2.pretty(ip) + ' > ' + geoIp2.pretty(r.range[1]));
44
- }
45
-
46
- const te = +new Date();
47
-
48
-
49
- // f.forEach(data => {
50
- // console.log('%s bw %s & %s is %s', geoIp2.pretty(data[0]), geoIp2.pretty(data[1].range[0]), geoIp2.pretty(data[1].range[1]), data[1].country);
51
- // });
52
-
53
-
54
- console.log('Found %d (%d/%d) ips in %dms (%s ip/s) (%sμs/ip)', n, f.length, nf.length, te - ts, (n * 1000 / (te - ts)).toFixed(3), ((te - ts) * 1000 / n).toFixed(0));
55
- console.log('Took %d ms to startup', t2 - t1);
@@ -1,227 +0,0 @@
1
- const geoIp2 = require('../lib/main.js');
2
-
3
- describe('GeoIP2', () => {
4
- describe('#testLookup', () => {
5
- it('should return data about IPv4', () => {
6
- const ip = '1.1.1.1';
7
- const actual = geoIp2.lookup(ip);
8
- expect(actual).toBeTruthy();
9
- });
10
-
11
- it('should return data about IPv6', () => {
12
- const actual = geoIp2.lookup('2606:4700:4700::64');
13
- expect(actual).toBeTruthy();
14
- });
15
- });
16
-
17
- describe('#testDataIP4', () => {
18
- it('should match data for IPv4 - PL', () => {
19
- const actual = geoIp2.lookup('104.113.255.255');
20
- expect(actual.country).toBe('PL');
21
- expect(actual.region).toBe('14');
22
- expect(actual.eu).toBe('1');
23
- expect(actual.timezone).toBe('Europe/Warsaw');
24
- expect(actual.city).toBe('Warsaw');
25
- expect(actual.ll).toBeTruthy();
26
- expect(actual.metro).toBe(0);
27
- expect(actual.area).toBe(20);
28
- });
29
-
30
- it('should match data for IPv4 - US', () => {
31
- const actual = geoIp2.lookup('72.229.28.185');
32
- expect(actual.country).toBe('US');
33
- expect(actual.region).toBe('NY');
34
- expect(actual.eu).toBe('0');
35
- expect(actual.timezone).toBe('America/New_York');
36
- expect(actual.city).toBe('New York');
37
- expect(actual.ll).toBeTruthy();
38
- expect(actual.metro).toBe(501);
39
- expect(actual.area).toBe(5);
40
- });
41
-
42
- it('should match data for IPv4 - JP', () => {
43
- const actual = geoIp2.lookup('210.138.184.59');
44
- expect(actual.country).toBe('JP');
45
- expect(actual.eu).toBe('0');
46
- expect(actual.timezone).toBe('Asia/Tokyo');
47
- expect(actual.city).toBe('');
48
- expect(actual.ll).toBeTruthy();
49
- expect(actual.metro).toBe(0);
50
- expect(actual.area).toBe(500);
51
- });
52
-
53
- it('should match data for IPv4 - RU', () => {
54
- const actual = geoIp2.lookup('109.108.63.255');
55
- expect(actual.country).toBe('RU');
56
- expect(actual.region).toBe('IVA');
57
- expect(actual.eu).toBe('0');
58
- expect(actual.timezone).toBe('Europe/Moscow');
59
- expect(actual.city).toBe('Kineshma');
60
- expect(actual.ll).toBeTruthy();
61
- expect(actual.metro).toBe(0);
62
- expect(actual.area).toBe(100);
63
- });
64
- });
65
-
66
- describe('#testDataIP6', () => {
67
- it('should match data for IPv6 - PL', () => {
68
- const actual = geoIp2.lookup('2a01:118f:30a:3900:c954:e6ef:8067:d4e8');
69
- expect(actual.country).toBe('PL');
70
- expect(actual.region).toBe('06');
71
- expect(actual.eu).toBe('1');
72
- expect(actual.timezone).toBe('Europe/Warsaw');
73
- expect(actual.city).toBe('Lublin');
74
- expect(actual.ll).toBeTruthy();
75
- expect(actual.metro).toBe(0);
76
- expect(actual.area).toBe(100);
77
- });
78
-
79
- it('should match data for IPv6 - NL ', () => {
80
- const actual = geoIp2.lookup('2001:1c04:400::1');
81
- expect(actual.country).toBe('NL');
82
- expect(actual.region).toBe('NH');
83
- expect(actual.eu).toBe('1');
84
- expect(actual.timezone).toBe('Europe/Amsterdam');
85
- expect(actual.city).toBe('Zandvoort');
86
- expect(actual.ll).toBeTruthy();
87
- expect(actual.metro).toBe(0);
88
- expect(actual.area).toBe(5);
89
- });
90
-
91
- it('should match data for IPv6 - JP', () => {
92
- const actual = geoIp2.lookup('2400:8500:1302:814:a163:44:173:238f');
93
- expect(actual.country).toBe('JP');
94
- expect(actual.region).toBe('');
95
- expect(actual.eu).toBe('0');
96
- expect(actual.timezone).toBe('Asia/Tokyo');
97
- expect(actual.city).toBe('');
98
- expect(actual.ll).toBeTruthy();
99
- expect(actual.metro).toBe(0);
100
- expect(actual.area).toBe(500);
101
- });
102
- });
103
-
104
- describe('#testUTF8', () => {
105
- it('should return UTF8 city name', () => {
106
- const actual = geoIp2.lookup('2.139.175.1');
107
- expect(actual.country).toBe('ES');
108
- expect(actual.city).toBe('Barcelona');
109
- expect(actual.timezone).toBe('Europe/Madrid');
110
- });
111
-
112
- it('should match data for IPv4 - PL', () => {
113
- const actual = geoIp2.lookup('86.63.89.41');
114
- expect(actual.country).toBe('PL');
115
- expect(actual.timezone).toBe('Europe/Warsaw');
116
- expect(actual.city).toBe('Piła');
117
- });
118
- });
119
-
120
- describe('#testMetro', () => {
121
- it('should match metro data', () => {
122
- const actual = geoIp2.lookup('23.240.63.68');
123
- expect(actual.metro).toBe(803);
124
- });
125
- });
126
-
127
- describe('#testIPv4MappedIPv6', () => {
128
- it('should match IPv4 mapped IPv6 data', () => {
129
- const actual = geoIp2.lookup('195.16.170.74');
130
- expect(actual.metro).toBe(0);
131
- });
132
- });
133
-
134
- describe('#testSyncReload', () => {
135
- it('should reload data synchronously', () => {
136
- const before4 = geoIp2.lookup('75.82.117.180');
137
- expect(before4).not.toBeNull();
138
- const before6 = geoIp2.lookup('::ffff:173.185.182.82');
139
- expect(before6).not.toBeNull();
140
-
141
- geoIp2.clear();
142
-
143
- const none4 = geoIp2.lookup('75.82.117.180');
144
- expect(none4).toBeNull();
145
- const none6 = geoIp2.lookup('::ffff:173.185.182.82');
146
- expect(none6).toBeNull();
147
-
148
- geoIp2.reloadDataSync();
149
-
150
- const after4 = geoIp2.lookup('75.82.117.180');
151
- expect(before4).toEqual(after4);
152
- const after6 = geoIp2.lookup('::ffff:173.185.182.82');
153
- expect(before6).toEqual(after6);
154
- });
155
- });
156
-
157
- describe('#testAsyncReload', () => {
158
- it('should reload data asynchronously', (done) => {
159
- const before4 = geoIp2.lookup('75.82.117.180');
160
- expect(before4).not.toBeNull();
161
- const before6 = geoIp2.lookup('::ffff:173.185.182.82');
162
- expect(before6).not.toBeNull();
163
-
164
- geoIp2.clear();
165
-
166
- const none4 = geoIp2.lookup('75.82.117.180');
167
- expect(none4).toBeNull();
168
- const none6 = geoIp2.lookup('::ffff:173.185.182.82');
169
- expect(none6).toBeNull();
170
-
171
- geoIp2.reloadData(() => {
172
- const after4 = geoIp2.lookup('75.82.117.180');
173
- expect(before4).toEqual(after4);
174
- const after6 = geoIp2.lookup('::ffff:173.185.182.82');
175
- expect(before6).toEqual(after6);
176
-
177
- done();
178
- });
179
- });
180
- });
181
-
182
- describe('#testInvalidIP', () => {
183
- it('should return null for an invalid IP address', () => {
184
- const ip = 'invalid_ip_address';
185
- const actual = geoIp2.lookup(ip);
186
- expect(actual).toBeNull();
187
- });
188
- });
189
-
190
- describe('#testEmptyIP', () => {
191
- it('should return null for an empty IP address', () => {
192
- const actual = geoIp2.lookup('');
193
- expect(actual).toBeNull();
194
- });
195
- });
196
-
197
- describe('#testNullIP', () => {
198
- it('should return null for a null IP address', () => {
199
- const actual = geoIp2.lookup(null);
200
- expect(actual).toBeNull();
201
- });
202
- });
203
-
204
- describe('#testUnknownIP', () => {
205
- it('should return null for an unknown IP address', () => {
206
- const ip = '192.168.0.1'; // Private IP address
207
- const actual = geoIp2.lookup(ip);
208
- expect(actual).toBeNull();
209
- });
210
- });
211
-
212
- describe('#testNoDataForIP', () => {
213
- it('should return null for an IP address with no data', () => {
214
- const ip = '203.0.113.0'; // Example IP with no data
215
- const actual = geoIp2.lookup(ip);
216
- expect(actual).toBeNull();
217
- });
218
- });
219
-
220
- describe('#testSpecialCharactersIP', () => {
221
- it('should return null for an IP address with special characters', () => {
222
- const ip = '20.24.@.&'; // IP with special characters
223
- const actual = geoIp2.lookup(ip);
224
- expect(actual).toBeNull();
225
- });
226
- });
227
- });
@@ -1,4 +0,0 @@
1
- // eslint-disable-next-line no-unused-vars
2
- const geoIp2 = require('../lib/main.js');
3
-
4
- console.log(process.memoryUsage());
package/test/other.js DELETED
@@ -1,6 +0,0 @@
1
- const geoIp2 = require('../lib/main.js');
2
-
3
- const ip = 34525252;
4
- const addr = geoIp2.pretty(ip);
5
-
6
- console.log(`Module version: ${geoIp2.version}\nIP: ${34525252}\nPretty: ${addr}`);
@@ -1,16 +0,0 @@
1
- const geoIp2 = require('../lib/main.js');
2
- const ip = '86.63.89.41';
3
-
4
- // Function
5
- const action = async () => {
6
- const data = geoIp2.lookup(ip);
7
- console.log(data);
8
- };
9
-
10
- // Interval
11
- setInterval(async () => {
12
- await action();
13
- }, 100);
14
-
15
- // Run
16
- (async () => await action())();
@@ -1 +0,0 @@
1
- const{name:e,version:t}=require('../package.json'),n=`Mozilla/5.0 (compatible; ${e}/${t}; +https://github.com/sefinek/geoip-lite2)`,o=require('fs'),r=require('http'),s=require('https'),i=require('path'),c=require('zlib'),a=require('readline'),l=require('async'),{decodeStream:u}=require('iconv-lite'),d=require('rimraf').sync,p=require('adm-zip'),f=require('../lib/utils.js'),{Address6:h,Address4:g}=require('ip-address'),w=process.argv.slice(2);let m=w.find(e=>null!==e.match(/^license_key=[a-zA-Z0-9]+/));void 0===m&&void 0!==process.env.LICENSE_KEY&&(m=`license_key=${process.env.LICENSE_KEY}`);let y=w.find(e=>null!==e.match(/^geoDataDir=[\w./]+/));void 0===y&&void 0!==process.env.GEODATADIR&&(y=`geoDataDir=${process.env.GEODATADIR}`);let I=i.resolve(__dirname,'..','geoip-data');void 0!==y&&(I=i.resolve(process.cwd(),y.split('=')[1]),o.existsSync(I)||(console.log('ERROR: Directory doesn\'t exist: '+I),process.exit(1)));const v=process.env.GEOTMPDIR||i.resolve(__dirname,'..','tmp'),S={},E={NaN:-1},x=[{type:'country',url:`https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&suffix=zip&${m}`,checksum:`https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&suffix=zip.sha256&${m}`,fileName:'GeoLite2-Country-CSV.zip',src:['GeoLite2-Country-Locations-en.csv','GeoLite2-Country-Blocks-IPv4.csv','GeoLite2-Country-Blocks-IPv6.csv'],dest:['','geoip-country.dat','geoip-country6.dat']},{type:'city',url:`https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City-CSV&suffix=zip&${m}`,checksum:`https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City-CSV&suffix=zip.sha256&${m}`,fileName:'GeoLite2-City-CSV.zip',src:['GeoLite2-City-Locations-en.csv','GeoLite2-City-Blocks-IPv4.csv','GeoLite2-City-Blocks-IPv6.csv'],dest:['geoip-city-names.dat','geoip-city.dat','geoip-city6.dat']}];function k(e){const t=i.dirname(e);o.existsSync(t)||o.mkdirSync(t)}const D=/^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/,C=/(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;function R(e){if(!D.test(e)&&(e=function(e){let t=0,n=-1;for(e=e.replace(/""/,'\\"').replace(/'/g,'\\\'');t<e.length&&n<e.length;)t=n,n=e.indexOf(',',t+1),n<0&&(n=e.length),e.indexOf('\'',t||0)>-1&&e.indexOf('\'',t)<n&&'"'!=e[t+1]&&'"'!=e[n-1]&&(n=(e=e.substr(0,t+1)+'"'+e.substr(t+1,n-t-1)+'"'+e.substr(n,e.length-n)).indexOf(',',n+1),n<0&&(n=e.length));return e}(e),!D.test(e)))return null;const t=[];return e.replace(C,(e,n,o,r)=>(void 0!==n?t.push(n.replace(/\\'/g,'\'')):void 0!==o?t.push(o.replace(/\\"/g,'"').replace(/\\'/g,'\'')):void 0!==r&&t.push(r),'')),/,\s*$/.test(e)&&t.push(''),t}function B(e){const t=new URL(e),o={protocol:t.protocol,host:t.host,path:t.pathname+t.search,headers:{'User-Agent':n}};if(process.env.http_proxy||process.env.https_proxy)try{const e=require('https-proxy-agent');o.agent=new e(process.env.http_proxy||process.env.https_proxy)}catch(e){console.error(`Install https-proxy-agent to use an HTTP/HTTPS proxy. ${e.message}`),process.exit(-1)}return o}function _(e,t){if(-1!==w.indexOf('force'))return t(null,e);const n=e.checksum;if(void 0===n)return t(null,e);o.readFile(i.join(I,`${e.type}.checksum`),{encoding:'utf8'},(o,i)=>{!o&&i&&i.length&&(e.checkValue=i),console.log('Checking',e.fileName);var c=s.get(B(n),function n(o){const i=o.statusCode;if([301,302,303,307,308].includes(i))return s.get(B(o.headers.location),n);200!==i&&(console.error(o.data),console.error('ERROR: HTTP Request Failed [%d %s]',i,r.STATUS_CODES[i]),c.end(),process.exit(1));let a='';o.on('data',e=>{a+=e}),o.on('end',()=>{a&&a.length?a===e.checkValue?(console.log(`Database "${e.type}" is up to date`),e.skip=!0):(console.log(`Database "${e.type}" has new data`),e.checkValue=a):(console.error(`ERROR: Could not retrieve checksum for ${e.type}. Aborting.`),console.error('Run with "force" to update without checksum'),c.end(),process.exit(1)),t(null,e)})})})}function A(e,t){if(e.skip)return t(null,null,null,e);const n=e.url;let a=e.fileName;const l='.gz'===i.extname(a);l&&(a=a.replace('.gz',''));const u=i.join(v,a);if(o.existsSync(u))return t(null,u,a,e);console.log('Fetching',a),k(u);var d=s.get(B(n),function n(i){const p=i.statusCode;if([301,302,303,307,308].includes(p))return s.get(B(i.headers.location),n);let f;200!==p&&(console.error('ERROR: HTTP Request Failed [%d %s]',p,r.STATUS_CODES[p]),d.end(),process.exit(1));const h=o.createWriteStream(u);f=l?i.pipe(c.createGunzip()).pipe(h):i.pipe(h),f.on('close',()=>{console.log(' DONE'),t(null,u,a,e)})});process.stdout.write(`Retrieving ${a}...`)}function O(e,t,n,r){if(n.skip)return r(null,n);'.zip'!==i.extname(t)||(process.stdout.write('Extracting '+t+'...'),new p(e).getEntries().forEach(e=>{if(e.isDirectory)return;const t=e.entryName.split('/'),n=t[t.length-1],r=i.join(v,n);o.writeFileSync(r,e.getData())}),console.log(' DONE')),r(null,n)}async function b(e,t){var n,r;let s=0;function c(e){const t=R(e);if(!t||t.length<6)return console.warn('weird line: %s::',e);let o,i,c;s++;const a=S[t[1]];let l,u,d;if(a){if(t[0].match(/:/)){for(u=34,c=new h(t[0]),o=f.aton6(c.startAddress().correctForm()),i=f.aton6(c.endAddress().correctForm()),l=Buffer.alloc(u),d=0;d<o.length;d++)l.writeUInt32BE(o[d],4*d);for(d=0;d<i.length;d++)l.writeUInt32BE(i[d],16+4*d)}else u=10,c=new g(t[0]),o=parseInt(c.startAddress().bigInt(),10),i=parseInt(c.endAddress().bigInt(),10),l=Buffer.alloc(u),l.fill(0),l.writeUInt32BE(o,0),l.writeUInt32BE(i,4);return l.write(a,u-2),Date.now()-n>5e3&&(n=Date.now(),process.stdout.write(`\nStill working (${s})...`)),r._writableState.needDrain?new Promise(e=>{r.write(l,e)}):r.write(l)}}const l=i.join(I,t),u=i.join(v,e);d(l),k(l),process.stdout.write('\nProcessing data (may take a moment)...'),n=Date.now(),r=o.createWriteStream(l);const p=a.createInterface({input:o.createReadStream(u),crlfDelay:1/0});let w=0;for await(const e of p)w++,1!==w&&await c(e);r.close(),console.log(' DONE')}async function $(e,t){var n,r;let s=0;async function c(e){if(e.match(/^Copyright/)||!e.match(/\d/))return;const t=R(e);if(!t)return console.warn('Weird line: %s::',e);let o,i,c,a,l,u,d,p,w,m;if(s++,t[0].match(/:/)){let e=0;for(u=48,c=new h(t[0]),o=f.aton6(c.startAddress().correctForm()),i=f.aton6(c.endAddress().correctForm()),a=parseInt(t[1],10),a=E[a],l=Buffer.alloc(u),l.fill(0),m=0;m<o.length;m++)l.writeUInt32BE(o[m],e),e+=4;for(m=0;m<i.length;m++)l.writeUInt32BE(i[m],e),e+=4;l.writeUInt32BE(a>>>0,32),d=Math.round(1e4*parseFloat(t[7])),p=Math.round(1e4*parseFloat(t[8])),w=parseInt(t[9],10),l.writeInt32BE(d,36),l.writeInt32BE(p,40),l.writeInt32BE(w,44)}else u=24,c=new g(t[0]),o=parseInt(c.startAddress().bigInt(),10),i=parseInt(c.endAddress().bigInt(),10),a=parseInt(t[1],10),a=E[a],l=Buffer.alloc(u),l.fill(0),l.writeUInt32BE(o>>>0,0),l.writeUInt32BE(i>>>0,4),l.writeUInt32BE(a>>>0,8),d=Math.round(1e4*parseFloat(t[7])),p=Math.round(1e4*parseFloat(t[8])),w=parseInt(t[9],10),l.writeInt32BE(d,12),l.writeInt32BE(p,16),l.writeInt32BE(w,20);return Date.now()-n>5e3&&(n=Date.now(),process.stdout.write('\nStill working ('+s+')...')),r._writableState.needDrain?new Promise(e=>{r.write(l,e)}):r.write(l)}const l=i.join(I,t),u=i.join(v,e);d(l),process.stdout.write('\nProcessing data (may take a moment)...'),n=Date.now(),r=o.createWriteStream(l);const p=a.createInterface({input:o.createReadStream(u),crlfDelay:1/0});let w=0;for await(const e of p)w++,1!==w&&await c(e);r.close()}function q(e,t){if(e.skip)return t(null,e);const n=e.type,r=e.src,s=e.dest;'country'===n?Array.isArray(r)?function(e,t){const n=i.join(v,e);process.stdout.write('Processing lookup data (may take a moment)...');const r=a.createInterface({input:o.createReadStream(n).pipe(u('latin1')),output:process.stdout,terminal:!1});let s=0;r.on('line',e=>{s>0&&function(e){const t=R(e);!t||t.length<6?console.log('Weird line: %s::',e):S[t[0]]=t[4]}(e),s++}),r.on('close',()=>{console.log(' DONE'),t()})}(r[0],()=>{b(r[1],s[1]).then(()=>b(r[2],s[2])).then(()=>{t(null,e)})}):b(r,s):'city'===n&&function(e,t,n){let r=null,s=0;const c=i.join(I,t),l=i.join(v,e);d(c);var p=o.openSync(c,'w');const f=a.createInterface({input:o.createReadStream(l).pipe(u('utf-8')),output:process.stdout,terminal:!1});let h=0;f.on('line',e=>{h>0&&function(e){if(e.match(/^Copyright/)||!e.match(/\d/))return;const t=Buffer.alloc(88),n=R(e);if(!n)return void console.warn('Weird line: %s::',e);r=parseInt(n[0]),E[r]=s;const i=n[4],c=n[6],a=n[10],l=parseInt(n[11]),u=n[12],d=n[13];t.fill(0),t.write(i,0),t.write(c,2),l&&t.writeInt32BE(l,5),t.write(d,9),t.write(u,10),t.write(a,42),o.writeSync(p,t,0,t.length,null),s++}(e),h++}),f.on('close',n)}(r[0],s[0],()=>{$(r[1],s[1]).then(()=>(console.log('\nCity data processed'),$(r[2],s[2]))).then(()=>{console.log(' DONE'),t(null,e)})})}function L(e,t){if(e.skip||!e.checkValue)return t();o.writeFile(i.join(I,e.type+'.checksum'),e.checkValue,'utf8',n=>{n&&console.log('Failed to Update checksums! Database:',e.type),t()})}m||(console.error('ERROR: Missing license_key'),process.exit(1)),d(v),k(v),l.eachSeries(x,(e,t)=>{l.seq(_,A,O,q,L)(e,t)},e=>{e?(console.error('Failed to update databases from MaxMind!',e),process.exit(1)):(console.log('Successfully updated databases from MaxMind'),-1!==w.indexOf('debug')||d(v),process.exit(0))});
File without changes