geoip-lite2 2.2.8-beta.6 → 2.2.8-beta.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/data/city.checksum +1 -1
- package/data/country.checksum +1 -1
- package/data/geoip-city-names.dat +0 -0
- package/data/geoip-city.dat +0 -0
- package/data/geoip-city6.dat +0 -0
- package/data/geoip-country.dat +0 -0
- package/data/geoip-country6.dat +0 -0
- package/fsWatcher.js +85 -0
- package/index.js +571 -0
- package/package.json +7 -7
- package/tools/updatedb.js +1 -1
- package/utils.js +103 -0
- package/dist/fsWatcher.js +0 -1
- package/dist/main.js +0 -1
- package/dist/utils.js +0 -1
package/data/city.checksum
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
1e2d74273ff207a2a7d129a195b300dbc45b22a4358cd3e45de17ae47ccab4f8 GeoLite2-City-CSV_20251128.zip
|
package/data/country.checksum
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
67ac2aeddc82fc748089eaf5b01edf2ce0895c0c383a4a3f6812270a93bb3333 GeoLite2-Country-CSV_20251128.zip
|
|
Binary file
|
package/data/geoip-city.dat
CHANGED
|
Binary file
|
package/data/geoip-city6.dat
CHANGED
|
Binary file
|
package/data/geoip-country.dat
CHANGED
|
Binary file
|
package/data/geoip-country6.dat
CHANGED
|
Binary file
|
package/fsWatcher.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// File System Watcher for Auto-Reloading GeoIP Data
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
const { access, constants, watch } = require('node:fs');
|
|
6
|
+
const { join } = require('node:path');
|
|
7
|
+
const FSWatcher = {};
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Watcher Management
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Takes an FSWatcher object and closes it.
|
|
15
|
+
* @param {string} name - The name of the watcher to close.
|
|
16
|
+
*/
|
|
17
|
+
const stopWatching = name => FSWatcher[name].close();
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// File System Watch with Debounce
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Takes a directory/file and watch for change. Upon change, call the callback.
|
|
25
|
+
*
|
|
26
|
+
* @param {String} name - name of this watcher
|
|
27
|
+
* @param {String} directory - path to the directory to watch
|
|
28
|
+
* @param {String} [filename] - (optional) specific filename to watch for, watches for all files in the directory if unspecified
|
|
29
|
+
* @param {Number} cdDelay - delay to wait before triggering the callback
|
|
30
|
+
* @param {Function} callback - function() - called when changes are detected
|
|
31
|
+
*/
|
|
32
|
+
const makeFsWatchFilter = (name, directory, filename, cdDelay, callback) => {
|
|
33
|
+
let cdId = null;
|
|
34
|
+
|
|
35
|
+
// Delete the cdId and callback the outer function
|
|
36
|
+
function timeoutCallback() {
|
|
37
|
+
cdId = null;
|
|
38
|
+
callback();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// This function is called when there is a change in the data directory
|
|
42
|
+
// It sets a timer to wait for the change to be completed
|
|
43
|
+
function onWatchEvent(event, changedFile) {
|
|
44
|
+
// Check to make sure changedFile is not null
|
|
45
|
+
if (!changedFile) return;
|
|
46
|
+
|
|
47
|
+
const filePath = join(directory, changedFile);
|
|
48
|
+
if (!filename || filename === changedFile) {
|
|
49
|
+
access(filePath, constants.F_OK, err => {
|
|
50
|
+
if (err) return console.error(err);
|
|
51
|
+
|
|
52
|
+
// At this point, a new file system activity has been detected,
|
|
53
|
+
// We have to wait for file transfer to be finished before moving on.
|
|
54
|
+
|
|
55
|
+
// If a cdId already exists, we delete it
|
|
56
|
+
if (cdId !== null) {
|
|
57
|
+
clearTimeout(cdId);
|
|
58
|
+
cdId = null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Once the cdDelay has passed, the timeoutCallback function will be called
|
|
62
|
+
cdId = setTimeout(timeoutCallback, cdDelay);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Manage the case where filename is missing (because it's optional)
|
|
68
|
+
if (typeof cdDelay === 'function') {
|
|
69
|
+
callback = cdDelay;
|
|
70
|
+
cdDelay = filename;
|
|
71
|
+
filename = null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (FSWatcher[name]) {
|
|
75
|
+
stopWatching(name);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
FSWatcher[name] = watch(directory, onWatchEvent);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Exports
|
|
83
|
+
// ============================================================================
|
|
84
|
+
|
|
85
|
+
module.exports = { makeFsWatchFilter, stopWatching };
|
package/index.js
ADDED
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Dependencies
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
const { open, fstat, read, close, openSync, fstatSync, readSync, closeSync } = require('node:fs');
|
|
6
|
+
const { join, resolve } = require('node:path');
|
|
7
|
+
const { isIP } = require('node:net');
|
|
8
|
+
const async = require('async');
|
|
9
|
+
const { aton4, aton6, cmp6, ntoa4, ntoa6, cmp } = require('./utils.js');
|
|
10
|
+
const fsWatcher = require('./fsWatcher.js');
|
|
11
|
+
const { version } = require('./package.json');
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Configuration
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
const watcherName = 'dataWatcher';
|
|
18
|
+
|
|
19
|
+
const geoDataDir = resolve(
|
|
20
|
+
__dirname,
|
|
21
|
+
global.geoDataDir || process.env.GEODATADIR || './data/'
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
const dataFiles = {
|
|
25
|
+
city: join(geoDataDir, 'geoip-city.dat'),
|
|
26
|
+
city6: join(geoDataDir, 'geoip-city6.dat'),
|
|
27
|
+
cityNames: join(geoDataDir, 'geoip-city-names.dat'),
|
|
28
|
+
country: join(geoDataDir, 'geoip-country.dat'),
|
|
29
|
+
country6: join(geoDataDir, 'geoip-country6.dat'),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const privateRange4 = [
|
|
33
|
+
[aton4('10.0.0.0'), aton4('10.255.255.255')],
|
|
34
|
+
[aton4('172.16.0.0'), aton4('172.31.255.255')],
|
|
35
|
+
[aton4('192.168.0.0'), aton4('192.168.255.255')],
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Cache Configuration
|
|
40
|
+
// ============================================================================
|
|
41
|
+
|
|
42
|
+
const conf4 = {
|
|
43
|
+
firstIP: null,
|
|
44
|
+
lastIP: null,
|
|
45
|
+
lastLine: 0,
|
|
46
|
+
locationBuffer: null,
|
|
47
|
+
locationRecordSize: 88,
|
|
48
|
+
mainBuffer: null,
|
|
49
|
+
recordSize: 24,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const conf6 = {
|
|
53
|
+
firstIP: null,
|
|
54
|
+
lastIP: null,
|
|
55
|
+
lastLine: 0,
|
|
56
|
+
mainBuffer: null,
|
|
57
|
+
recordSize: 48,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
let cache4 = { ...conf4 };
|
|
61
|
+
let cache6 = { ...conf6 };
|
|
62
|
+
|
|
63
|
+
const RECORD_SIZE = 10;
|
|
64
|
+
const RECORD_SIZE6 = 34;
|
|
65
|
+
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// Helper Functions
|
|
68
|
+
// ============================================================================
|
|
69
|
+
|
|
70
|
+
const removeNullTerminator = str => {
|
|
71
|
+
const nullIndex = str.indexOf('\0');
|
|
72
|
+
return nullIndex === -1 ? str : str.substring(0, nullIndex);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const readIp6 = (buffer, line, recordSize, offset) => {
|
|
76
|
+
const ipArray = [];
|
|
77
|
+
for (let i = 0; i < 2; i++) {
|
|
78
|
+
ipArray.push(buffer.readUInt32BE((line * recordSize) + (offset * 16) + (i * 4)));
|
|
79
|
+
}
|
|
80
|
+
return ipArray;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// IPv4 Lookup Function
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
const lookup4 = ip => {
|
|
88
|
+
let fline = 0;
|
|
89
|
+
let cline = cache4.lastLine;
|
|
90
|
+
let floor = cache4.lastIP;
|
|
91
|
+
let ceil = cache4.firstIP;
|
|
92
|
+
let line, locId;
|
|
93
|
+
|
|
94
|
+
const buffer = cache4.mainBuffer;
|
|
95
|
+
const locBuffer = cache4.locationBuffer;
|
|
96
|
+
const privateRange = privateRange4;
|
|
97
|
+
const recordSize = cache4.recordSize;
|
|
98
|
+
const locRecordSize = cache4.locationRecordSize;
|
|
99
|
+
|
|
100
|
+
const geoData = {
|
|
101
|
+
range: [null, null],
|
|
102
|
+
country: '',
|
|
103
|
+
region: '',
|
|
104
|
+
eu: '',
|
|
105
|
+
timezone: '',
|
|
106
|
+
city: '',
|
|
107
|
+
ll: [null, null],
|
|
108
|
+
metro: null,
|
|
109
|
+
area: null,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Outside IPv4 range
|
|
113
|
+
if (ip > cache4.lastIP || ip < cache4.firstIP) return null;
|
|
114
|
+
|
|
115
|
+
// Private IP
|
|
116
|
+
for (let i = 0; i < privateRange.length; i++) {
|
|
117
|
+
if (ip >= privateRange[i][0] && ip <= privateRange[i][1]) return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
while (true) {
|
|
121
|
+
line = Math.round((cline - fline) / 2) + fline;
|
|
122
|
+
const offset = line * recordSize;
|
|
123
|
+
floor = buffer.readUInt32BE(offset);
|
|
124
|
+
ceil = buffer.readUInt32BE(offset + 4);
|
|
125
|
+
|
|
126
|
+
if (floor <= ip && ceil >= ip) {
|
|
127
|
+
geoData.range = [floor, ceil];
|
|
128
|
+
|
|
129
|
+
if (recordSize === RECORD_SIZE) {
|
|
130
|
+
geoData.country = buffer.toString('utf8', offset + 8, offset + 10);
|
|
131
|
+
} else {
|
|
132
|
+
locId = buffer.readUInt32BE(offset + 8);
|
|
133
|
+
|
|
134
|
+
// -1>>>0 is a marker for "No Location Info"
|
|
135
|
+
if (-1 >>> 0 > locId) {
|
|
136
|
+
const locOffset = locId * locRecordSize;
|
|
137
|
+
geoData.country = removeNullTerminator(locBuffer.toString('utf8', locOffset, locOffset + 2));
|
|
138
|
+
geoData.region = removeNullTerminator(locBuffer.toString('utf8', locOffset + 2, locOffset + 5));
|
|
139
|
+
geoData.metro = locBuffer.readInt32BE(locOffset + 5);
|
|
140
|
+
geoData.ll[0] = buffer.readInt32BE(offset + 12) / 10000; // latitude
|
|
141
|
+
geoData.ll[1] = buffer.readInt32BE(offset + 16) / 10000; // longitude
|
|
142
|
+
geoData.area = buffer.readUInt32BE(offset + 20);
|
|
143
|
+
geoData.eu = removeNullTerminator(locBuffer.toString('utf8', locOffset + 9, locOffset + 10));
|
|
144
|
+
geoData.timezone = removeNullTerminator(locBuffer.toString('utf8', locOffset + 10, locOffset + 42));
|
|
145
|
+
geoData.city = removeNullTerminator(locBuffer.toString('utf8', locOffset + 42, locOffset + locRecordSize));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return geoData;
|
|
150
|
+
} else if (fline === cline) {
|
|
151
|
+
return null;
|
|
152
|
+
} else if (fline === (cline - 1)) {
|
|
153
|
+
if (line === fline) {
|
|
154
|
+
fline = cline;
|
|
155
|
+
} else {
|
|
156
|
+
cline = fline;
|
|
157
|
+
}
|
|
158
|
+
} else if (floor > ip) {
|
|
159
|
+
cline = line;
|
|
160
|
+
} else if (ceil < ip) {
|
|
161
|
+
fline = line;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// ============================================================================
|
|
167
|
+
// IPv6 Lookup Function
|
|
168
|
+
// ============================================================================
|
|
169
|
+
|
|
170
|
+
const lookup6 = ip => {
|
|
171
|
+
const buffer = cache6.mainBuffer;
|
|
172
|
+
const recordSize = cache6.recordSize;
|
|
173
|
+
const locBuffer = cache4.locationBuffer;
|
|
174
|
+
const locRecordSize = cache4.locationRecordSize;
|
|
175
|
+
|
|
176
|
+
const geoData = {
|
|
177
|
+
range: [null, null],
|
|
178
|
+
country: '',
|
|
179
|
+
region: '',
|
|
180
|
+
eu: '',
|
|
181
|
+
timezone: '',
|
|
182
|
+
city: '',
|
|
183
|
+
ll: [null, null],
|
|
184
|
+
metro: null,
|
|
185
|
+
area: null,
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
let fline = 0;
|
|
189
|
+
let cline = cache6.lastLine;
|
|
190
|
+
let floor = cache6.lastIP;
|
|
191
|
+
let ceil = cache6.firstIP;
|
|
192
|
+
let line, locId;
|
|
193
|
+
|
|
194
|
+
if (cmp6(ip, cache6.lastIP) > 0 || cmp6(ip, cache6.firstIP) < 0) return null;
|
|
195
|
+
|
|
196
|
+
while (true) {
|
|
197
|
+
line = Math.round((cline - fline) / 2) + fline;
|
|
198
|
+
floor = readIp6(buffer, line, recordSize, 0);
|
|
199
|
+
ceil = readIp6(buffer, line, recordSize, 1);
|
|
200
|
+
|
|
201
|
+
if (cmp6(floor, ip) <= 0 && cmp6(ceil, ip) >= 0) {
|
|
202
|
+
const offset = line * recordSize;
|
|
203
|
+
if (recordSize === RECORD_SIZE6) {
|
|
204
|
+
geoData.country = removeNullTerminator(buffer.toString('utf8', offset + 32, offset + 34));
|
|
205
|
+
} else {
|
|
206
|
+
locId = buffer.readUInt32BE(offset + 32);
|
|
207
|
+
|
|
208
|
+
// -1>>>0 is a marker for "No Location Info"
|
|
209
|
+
if (-1 >>> 0 > locId) {
|
|
210
|
+
const locOffset = locId * locRecordSize;
|
|
211
|
+
geoData.country = removeNullTerminator(locBuffer.toString('utf8', locOffset, locOffset + 2));
|
|
212
|
+
geoData.region = removeNullTerminator(locBuffer.toString('utf8', locOffset + 2, locOffset + 5));
|
|
213
|
+
geoData.metro = locBuffer.readInt32BE(locOffset + 5);
|
|
214
|
+
geoData.ll[0] = buffer.readInt32BE(offset + 36) / 10000; // latitude
|
|
215
|
+
geoData.ll[1] = buffer.readInt32BE(offset + 40) / 10000; // longitude
|
|
216
|
+
geoData.area = buffer.readUInt32BE(offset + 44); // area
|
|
217
|
+
geoData.eu = removeNullTerminator(locBuffer.toString('utf8', locOffset + 9, locOffset + 10));
|
|
218
|
+
geoData.timezone = removeNullTerminator(locBuffer.toString('utf8', locOffset + 10, locOffset + 42));
|
|
219
|
+
geoData.city = removeNullTerminator(locBuffer.toString('utf8', locOffset + 42, locOffset + locRecordSize));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// We do not currently have detailed region/city info for IPv6, but finally have coords
|
|
223
|
+
return geoData;
|
|
224
|
+
} else if (fline === cline) {
|
|
225
|
+
return null;
|
|
226
|
+
} else if (fline === (cline - 1)) {
|
|
227
|
+
if (line === fline) {
|
|
228
|
+
fline = cline;
|
|
229
|
+
} else {
|
|
230
|
+
cline = fline;
|
|
231
|
+
}
|
|
232
|
+
} else if (cmp6(floor, ip) > 0) {
|
|
233
|
+
cline = line;
|
|
234
|
+
} else if (cmp6(ceil, ip) < 0) {
|
|
235
|
+
fline = line;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// ============================================================================
|
|
241
|
+
// IPv4-Mapped IPv6 Handler
|
|
242
|
+
// ============================================================================
|
|
243
|
+
|
|
244
|
+
const V6_PREFIX_1 = '0:0:0:0:0:FFFF:';
|
|
245
|
+
const V6_PREFIX_2 = '::FFFF:';
|
|
246
|
+
const get4mapped = ip => {
|
|
247
|
+
const ipv6 = ip.toUpperCase();
|
|
248
|
+
if (ipv6.startsWith(V6_PREFIX_1)) return ipv6.substring(V6_PREFIX_1.length);
|
|
249
|
+
if (ipv6.startsWith(V6_PREFIX_2)) return ipv6.substring(V6_PREFIX_2.length);
|
|
250
|
+
return null;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
// ============================================================================
|
|
254
|
+
// Data Loading Functions - IPv4
|
|
255
|
+
// ============================================================================
|
|
256
|
+
|
|
257
|
+
function preload(callback) {
|
|
258
|
+
let datFile;
|
|
259
|
+
let datSize;
|
|
260
|
+
const asyncCache = { ...conf4 };
|
|
261
|
+
|
|
262
|
+
// When the preload function receives a callback, do the task asynchronously
|
|
263
|
+
if (typeof arguments[0] === 'function') {
|
|
264
|
+
async.series([
|
|
265
|
+
cb => {
|
|
266
|
+
async.series([
|
|
267
|
+
cb2 => {
|
|
268
|
+
open(dataFiles.cityNames, 'r', (err, file) => {
|
|
269
|
+
datFile = file;
|
|
270
|
+
cb2(err);
|
|
271
|
+
});
|
|
272
|
+
},
|
|
273
|
+
cb2 => {
|
|
274
|
+
fstat(datFile, (err, stats) => {
|
|
275
|
+
datSize = stats.size;
|
|
276
|
+
asyncCache.locationBuffer = Buffer.alloc(datSize);
|
|
277
|
+
cb2(err);
|
|
278
|
+
});
|
|
279
|
+
},
|
|
280
|
+
cb2 => {
|
|
281
|
+
read(datFile, asyncCache.locationBuffer, 0, datSize, 0, cb2);
|
|
282
|
+
},
|
|
283
|
+
cb2 => {
|
|
284
|
+
close(datFile, cb2);
|
|
285
|
+
},
|
|
286
|
+
cb2 => {
|
|
287
|
+
open(dataFiles.city, 'r', (err, file) => {
|
|
288
|
+
datFile = file;
|
|
289
|
+
cb2(err);
|
|
290
|
+
});
|
|
291
|
+
},
|
|
292
|
+
cb2 => {
|
|
293
|
+
fstat(datFile, (err, stats) => {
|
|
294
|
+
datSize = stats.size;
|
|
295
|
+
cb2(err);
|
|
296
|
+
});
|
|
297
|
+
},
|
|
298
|
+
], err => {
|
|
299
|
+
if (err) {
|
|
300
|
+
if (err.code !== 'ENOENT' && err.code !== 'EBADF') {
|
|
301
|
+
throw err;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
open(dataFiles.country, 'r', (err, file) => {
|
|
305
|
+
if (err) {
|
|
306
|
+
cb(err);
|
|
307
|
+
} else {
|
|
308
|
+
datFile = file;
|
|
309
|
+
fstat(datFile, (err, stats) => {
|
|
310
|
+
datSize = stats.size;
|
|
311
|
+
asyncCache.recordSize = RECORD_SIZE;
|
|
312
|
+
|
|
313
|
+
cb();
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
} else {
|
|
319
|
+
cb();
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
}, () => {
|
|
323
|
+
asyncCache.mainBuffer = Buffer.alloc(datSize);
|
|
324
|
+
|
|
325
|
+
async.series([
|
|
326
|
+
cb2 => {
|
|
327
|
+
read(datFile, asyncCache.mainBuffer, 0, datSize, 0, cb2);
|
|
328
|
+
},
|
|
329
|
+
cb2 => {
|
|
330
|
+
close(datFile, cb2);
|
|
331
|
+
},
|
|
332
|
+
], err => {
|
|
333
|
+
if (!err) {
|
|
334
|
+
asyncCache.lastLine = (datSize / asyncCache.recordSize) - 1;
|
|
335
|
+
asyncCache.lastIP = asyncCache.mainBuffer.readUInt32BE((asyncCache.lastLine * asyncCache.recordSize) + 4);
|
|
336
|
+
asyncCache.firstIP = asyncCache.mainBuffer.readUInt32BE(0);
|
|
337
|
+
cache4 = asyncCache;
|
|
338
|
+
}
|
|
339
|
+
callback(err);
|
|
340
|
+
});
|
|
341
|
+
},
|
|
342
|
+
]);
|
|
343
|
+
} else {
|
|
344
|
+
try {
|
|
345
|
+
datFile = openSync(dataFiles.cityNames, 'r');
|
|
346
|
+
datSize = fstatSync(datFile).size;
|
|
347
|
+
if (datSize === 0) {
|
|
348
|
+
const err = new Error('Empty file');
|
|
349
|
+
err.code = 'EMPTY_FILE';
|
|
350
|
+
throw err;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
cache4.locationBuffer = Buffer.alloc(datSize);
|
|
354
|
+
readSync(datFile, cache4.locationBuffer, 0, datSize, 0);
|
|
355
|
+
closeSync(datFile);
|
|
356
|
+
|
|
357
|
+
datFile = openSync(dataFiles.city, 'r');
|
|
358
|
+
datSize = fstatSync(datFile).size;
|
|
359
|
+
} catch (err) {
|
|
360
|
+
if (err.code !== 'ENOENT' && err.code !== 'EBADF' && err.code !== 'EMPTY_FILE') {
|
|
361
|
+
throw err;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
datFile = openSync(dataFiles.country, 'r');
|
|
365
|
+
datSize = fstatSync(datFile).size;
|
|
366
|
+
cache4.recordSize = RECORD_SIZE;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
cache4.mainBuffer = Buffer.alloc(datSize);
|
|
370
|
+
readSync(datFile, cache4.mainBuffer, 0, datSize, 0);
|
|
371
|
+
closeSync(datFile);
|
|
372
|
+
|
|
373
|
+
cache4.lastLine = (datSize / cache4.recordSize) - 1;
|
|
374
|
+
cache4.lastIP = cache4.mainBuffer.readUInt32BE((cache4.lastLine * cache4.recordSize) + 4);
|
|
375
|
+
cache4.firstIP = cache4.mainBuffer.readUInt32BE(0);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// ============================================================================
|
|
380
|
+
// Data Loading Functions - IPv6
|
|
381
|
+
// ============================================================================
|
|
382
|
+
|
|
383
|
+
function preload6(callback) {
|
|
384
|
+
let datFile;
|
|
385
|
+
let datSize;
|
|
386
|
+
const asyncCache6 = { ...conf6 };
|
|
387
|
+
|
|
388
|
+
// When the preload function receives a callback, do the task asynchronously
|
|
389
|
+
if (typeof arguments[0] === 'function') {
|
|
390
|
+
async.series([
|
|
391
|
+
cb => {
|
|
392
|
+
async.series([
|
|
393
|
+
cb2 => {
|
|
394
|
+
open(dataFiles.city6, 'r', (err, file) => {
|
|
395
|
+
datFile = file;
|
|
396
|
+
cb2(err);
|
|
397
|
+
});
|
|
398
|
+
},
|
|
399
|
+
cb2 => {
|
|
400
|
+
fstat(datFile, (err, stats) => {
|
|
401
|
+
datSize = stats.size;
|
|
402
|
+
cb2(err);
|
|
403
|
+
});
|
|
404
|
+
},
|
|
405
|
+
], err => {
|
|
406
|
+
if (err) {
|
|
407
|
+
if (err.code !== 'ENOENT' && err.code !== 'EBADF') {
|
|
408
|
+
throw err;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
open(dataFiles.country6, 'r', (err, file) => {
|
|
412
|
+
if (err) {
|
|
413
|
+
cb(err);
|
|
414
|
+
} else {
|
|
415
|
+
datFile = file;
|
|
416
|
+
fstat(datFile, (err, stats) => {
|
|
417
|
+
datSize = stats.size;
|
|
418
|
+
asyncCache6.recordSize = RECORD_SIZE6;
|
|
419
|
+
|
|
420
|
+
cb();
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
} else {
|
|
425
|
+
cb();
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
}, () => {
|
|
429
|
+
asyncCache6.mainBuffer = Buffer.alloc(datSize);
|
|
430
|
+
|
|
431
|
+
async.series([
|
|
432
|
+
cb2 => {
|
|
433
|
+
read(datFile, asyncCache6.mainBuffer, 0, datSize, 0, cb2);
|
|
434
|
+
},
|
|
435
|
+
cb2 => {
|
|
436
|
+
close(datFile, cb2);
|
|
437
|
+
},
|
|
438
|
+
], err => {
|
|
439
|
+
if (!err) {
|
|
440
|
+
asyncCache6.lastLine = (datSize / asyncCache6.recordSize) - 1;
|
|
441
|
+
asyncCache6.lastIP = readIp6(asyncCache6.mainBuffer, asyncCache6.lastLine, asyncCache6.recordSize, 1);
|
|
442
|
+
asyncCache6.firstIP = readIp6(asyncCache6.mainBuffer, 0, asyncCache6.recordSize, 0);
|
|
443
|
+
cache6 = asyncCache6;
|
|
444
|
+
}
|
|
445
|
+
callback(err);
|
|
446
|
+
});
|
|
447
|
+
},
|
|
448
|
+
]);
|
|
449
|
+
} else {
|
|
450
|
+
try {
|
|
451
|
+
datFile = openSync(dataFiles.city6, 'r');
|
|
452
|
+
datSize = fstatSync(datFile).size;
|
|
453
|
+
|
|
454
|
+
if (datSize === 0) {
|
|
455
|
+
const err = new Error('Empty file');
|
|
456
|
+
err.code = 'EMPTY_FILE';
|
|
457
|
+
throw err;
|
|
458
|
+
}
|
|
459
|
+
} catch (err) {
|
|
460
|
+
if (err.code !== 'ENOENT' && err.code !== 'EBADF' && err.code !== 'EMPTY_FILE') {
|
|
461
|
+
throw err;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
datFile = openSync(dataFiles.country6, 'r');
|
|
465
|
+
datSize = fstatSync(datFile).size;
|
|
466
|
+
cache6.recordSize = RECORD_SIZE6;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
cache6.mainBuffer = Buffer.alloc(datSize);
|
|
470
|
+
readSync(datFile, cache6.mainBuffer, 0, datSize, 0);
|
|
471
|
+
closeSync(datFile);
|
|
472
|
+
|
|
473
|
+
cache6.lastLine = (datSize / cache6.recordSize) - 1;
|
|
474
|
+
cache6.lastIP = readIp6(cache6.mainBuffer, cache6.lastLine, cache6.recordSize, 1);
|
|
475
|
+
cache6.firstIP = readIp6(cache6.mainBuffer, 0, cache6.recordSize, 0);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// ============================================================================
|
|
480
|
+
// Public API
|
|
481
|
+
// ============================================================================
|
|
482
|
+
|
|
483
|
+
module.exports = {
|
|
484
|
+
cmp,
|
|
485
|
+
|
|
486
|
+
lookup: ip => {
|
|
487
|
+
if (!ip) {
|
|
488
|
+
return null;
|
|
489
|
+
} else if (typeof ip === 'number') {
|
|
490
|
+
return lookup4(ip);
|
|
491
|
+
} else if (isIP(ip) === 4) {
|
|
492
|
+
return lookup4(aton4(ip));
|
|
493
|
+
} else if (isIP(ip) === 6) {
|
|
494
|
+
const ipv4 = get4mapped(ip);
|
|
495
|
+
if (ipv4) {
|
|
496
|
+
return lookup4(aton4(ipv4));
|
|
497
|
+
} else {
|
|
498
|
+
return lookup6(aton6(ip));
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return null;
|
|
503
|
+
},
|
|
504
|
+
|
|
505
|
+
pretty: n => {
|
|
506
|
+
if (typeof n === 'string') {
|
|
507
|
+
return n;
|
|
508
|
+
} else if (typeof n === 'number') {
|
|
509
|
+
return ntoa4(n);
|
|
510
|
+
} else if (Array.isArray(n)) {
|
|
511
|
+
return ntoa6(n);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return n;
|
|
515
|
+
},
|
|
516
|
+
|
|
517
|
+
// Start watching for data updates. The watcher waits one minute for file transfer to
|
|
518
|
+
// complete before triggering the callback.
|
|
519
|
+
startWatchingDataUpdate: callback => {
|
|
520
|
+
fsWatcher.makeFsWatchFilter(watcherName, geoDataDir, 60 * 1000, () => {
|
|
521
|
+
// Reload data
|
|
522
|
+
async.series([
|
|
523
|
+
cb => {
|
|
524
|
+
preload(cb);
|
|
525
|
+
}, cb => {
|
|
526
|
+
preload6(cb);
|
|
527
|
+
},
|
|
528
|
+
], callback);
|
|
529
|
+
});
|
|
530
|
+
},
|
|
531
|
+
|
|
532
|
+
// Stop watching for data updates.
|
|
533
|
+
stopWatchingDataUpdate: () => fsWatcher.stopWatching(watcherName),
|
|
534
|
+
|
|
535
|
+
// Clear data
|
|
536
|
+
clear: () => {
|
|
537
|
+
cache4 = { ...conf4 };
|
|
538
|
+
cache6 = { ...conf6 };
|
|
539
|
+
},
|
|
540
|
+
|
|
541
|
+
// Reload data synchronously
|
|
542
|
+
reloadDataSync: () => {
|
|
543
|
+
preload();
|
|
544
|
+
preload6();
|
|
545
|
+
},
|
|
546
|
+
|
|
547
|
+
// Reload data asynchronously
|
|
548
|
+
reloadData: callback => {
|
|
549
|
+
// Reload data
|
|
550
|
+
async.series([
|
|
551
|
+
cb => {
|
|
552
|
+
preload(cb);
|
|
553
|
+
},
|
|
554
|
+
cb => {
|
|
555
|
+
preload6(cb);
|
|
556
|
+
},
|
|
557
|
+
], callback);
|
|
558
|
+
},
|
|
559
|
+
|
|
560
|
+
version,
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
// ============================================================================
|
|
564
|
+
// Initialize - Load data on module startup
|
|
565
|
+
// ============================================================================
|
|
566
|
+
|
|
567
|
+
preload();
|
|
568
|
+
preload6();
|
|
569
|
+
|
|
570
|
+
// lookup4 = gen_lookup('geoip-country.dat', 4);
|
|
571
|
+
// lookup6 = gen_lookup('geoip-country6.dat', 16);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "geoip-lite2",
|
|
3
|
-
"version": "2.2.8-beta.
|
|
3
|
+
"version": "2.2.8-beta.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,7 +52,7 @@
|
|
|
52
52
|
"license": "Apache-2.0",
|
|
53
53
|
"author": "Philip Tellis <philip@bluesmoon.info> (https://bluesmoon.info)",
|
|
54
54
|
"type": "commonjs",
|
|
55
|
-
"main": "
|
|
55
|
+
"main": "index.js",
|
|
56
56
|
"types": "index.d.ts",
|
|
57
57
|
"directories": {
|
|
58
58
|
"lib": "lib",
|
|
@@ -60,17 +60,18 @@
|
|
|
60
60
|
},
|
|
61
61
|
"files": [
|
|
62
62
|
"data",
|
|
63
|
-
"dist",
|
|
64
63
|
"tools",
|
|
65
64
|
"AUTHORS",
|
|
65
|
+
"fsWatcher.js",
|
|
66
66
|
"index.d.ts",
|
|
67
|
+
"index.js",
|
|
67
68
|
"LICENSE",
|
|
68
|
-
"README.md"
|
|
69
|
+
"README.md",
|
|
70
|
+
"utils.js"
|
|
69
71
|
],
|
|
70
72
|
"scripts": {
|
|
71
73
|
"lint": "eslint .",
|
|
72
74
|
"lint:fix": "eslint . --fix",
|
|
73
|
-
"minify": "node minify.js",
|
|
74
75
|
"test": "jest test",
|
|
75
76
|
"up": "ncu -u && npm install && npm update && npm audit fix",
|
|
76
77
|
"updatedb": "node tools/updatedb.js",
|
|
@@ -87,8 +88,7 @@
|
|
|
87
88
|
"devDependencies": {
|
|
88
89
|
"@eslint/js": "^9.39.1",
|
|
89
90
|
"globals": "^16.5.0",
|
|
90
|
-
"jest": "^30.2.0"
|
|
91
|
-
"terser": "^5.44.1"
|
|
91
|
+
"jest": "^30.2.0"
|
|
92
92
|
},
|
|
93
93
|
"engines": {
|
|
94
94
|
"node": ">=20.0.0"
|
package/tools/updatedb.js
CHANGED
|
@@ -23,7 +23,7 @@ const async = require('async');
|
|
|
23
23
|
const { decodeStream } = require('iconv-lite');
|
|
24
24
|
const rimraf = require('rimraf').sync;
|
|
25
25
|
const AdmZip = require('adm-zip');
|
|
26
|
-
const utils = require('../
|
|
26
|
+
const utils = require('../utils.js');
|
|
27
27
|
const { Address6, Address4 } = require('ip-address');
|
|
28
28
|
|
|
29
29
|
// ============================================================================
|
package/utils.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Utility Functions for IP Address Conversion and Comparison
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
const utils = module.exports = {};
|
|
6
|
+
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// IPv4 Conversion Functions
|
|
9
|
+
// ============================================================================
|
|
10
|
+
|
|
11
|
+
utils.aton4 = a => {
|
|
12
|
+
const parts = a.split('.');
|
|
13
|
+
return ((parseInt(parts[0], 10) << 24) >>> 0) + ((parseInt(parts[1], 10) << 16) >>> 0) + ((parseInt(parts[2], 10) << 8) >>> 0) + (parseInt(parts[3], 10) >>> 0);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
utils.ntoa4 = n => {
|
|
17
|
+
return ((n >>> 24) & 0xff) + '.' + ((n >>> 16) & 0xff) + '.' + ((n >>> 8) & 0xff) + '.' + (n & 0xff);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// IPv6 Conversion Functions
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
utils.aton6 = a => {
|
|
25
|
+
a = a.replace(/"/g, '').split(':');
|
|
26
|
+
|
|
27
|
+
const l = a.length - 1;
|
|
28
|
+
let i;
|
|
29
|
+
|
|
30
|
+
if (a[l] === '') {
|
|
31
|
+
a[l] = 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (l < 7) {
|
|
35
|
+
a.length = 8;
|
|
36
|
+
|
|
37
|
+
for (i = l; i >= 0 && a[i] !== ''; i--) {
|
|
38
|
+
a[7 - l + i] = a[i];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (i = 0; i < 8; i++) {
|
|
43
|
+
if (!a[i]) {
|
|
44
|
+
a[i] = 0;
|
|
45
|
+
} else {
|
|
46
|
+
a[i] = parseInt(a[i], 16);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const r = [];
|
|
51
|
+
for (i = 0; i < 4; i++) {
|
|
52
|
+
r.push(((a[2 * i] << 16) + a[2 * i + 1]) >>> 0);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return r;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
utils.ntoa6 = n => {
|
|
59
|
+
let a = '[';
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < n.length; i++) {
|
|
62
|
+
a += (n[i] >>> 16).toString(16) + ':';
|
|
63
|
+
a += (n[i] & 0xffff).toString(16) + ':';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
a = a.replace(/:$/, ']').replace(/:0+/g, ':').replace(/::+/, '::');
|
|
67
|
+
return a;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// Comparison Functions
|
|
72
|
+
// ============================================================================
|
|
73
|
+
|
|
74
|
+
utils.cmp = (a, b) => {
|
|
75
|
+
if (typeof a === 'number' && typeof b === 'number') return (a < b ? -1 : (a > b ? 1 : 0));
|
|
76
|
+
if (a instanceof Array && b instanceof Array) return utils.cmp6(a, b);
|
|
77
|
+
|
|
78
|
+
return null;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
utils.cmp6 = (a, b) => {
|
|
82
|
+
for (let ii = 0; ii < 2; ii++) {
|
|
83
|
+
if (a[ii] < b[ii]) return -1;
|
|
84
|
+
if (a[ii] > b[ii]) return 1;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return 0;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// ============================================================================
|
|
91
|
+
// IP Address Validation
|
|
92
|
+
// ============================================================================
|
|
93
|
+
|
|
94
|
+
utils.isPrivateIP = addr => {
|
|
95
|
+
const str = addr.toString();
|
|
96
|
+
return str.startsWith('10.') ||
|
|
97
|
+
str.startsWith('192.168.') ||
|
|
98
|
+
str.startsWith('172.16.') ||
|
|
99
|
+
str.startsWith('127.') ||
|
|
100
|
+
str.startsWith('169.254.') ||
|
|
101
|
+
str.startsWith('fc00:') ||
|
|
102
|
+
str.startsWith('fe80:');
|
|
103
|
+
};
|
package/dist/fsWatcher.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
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
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const{open:e,fstat:r,read:t,close:n,openSync:i,fstatSync:o,readSync:a,closeSync:l}=require('node:fs'),{join:f,resolve:u}=require('node:path'),{isIP:c}=require('node:net'),s=require('async'),{aton4:d,aton6:B,cmp6:y,ntoa4:I,ntoa6:m,cmp:E}=require('./utils.js'),S=require('./fsWatcher.js'),{version:g}=require('../package.json'),z='dataWatcher',p=u(__dirname,global.geoDataDir||process.env.GEODATADIR||'../data/'),P={city:f(p,'geoip-city.dat'),city6:f(p,'geoip-city6.dat'),cityNames:f(p,'geoip-city-names.dat'),country:f(p,'geoip-country.dat'),country6:f(p,'geoip-country6.dat')},h=[[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')]],F={firstIP:null,lastIP:null,lastLine:0,locationBuffer:null,locationRecordSize:88,mainBuffer:null,recordSize:24},L={firstIP:null,lastIP:null,lastLine:0,mainBuffer:null,recordSize:48};let U={...F},D={...L};const N=e=>{const r=e.indexOf('\0');return-1===r?e:e.substring(0,r)},T=(e,r,t,n)=>{const i=[];for(let o=0;o<2;o++)i.push(e.readUInt32BE(r*t+16*n+4*o));return i},w=e=>{let r,t,n=0,i=U.lastLine,o=U.lastIP,a=U.firstIP;const l=U.mainBuffer,f=U.locationBuffer,u=h,c=U.recordSize,s=U.locationRecordSize,d={range:[null,null],country:'',region:'',eu:'',timezone:'',city:'',ll:[null,null],metro:null,area:null};if(e>U.lastIP||e<U.firstIP)return null;for(let r=0;r<u.length;r++)if(e>=u[r][0]&&e<=u[r][1])return null;for(;;){r=Math.round((i-n)/2)+n;const u=r*c;if(o=l.readUInt32BE(u),a=l.readUInt32BE(u+4),o<=e&&a>=e){if(d.range=[o,a],10===c)d.country=l.toString('utf8',u+8,u+10);else if(t=l.readUInt32BE(u+8),-1>>>0>t){const e=t*s;d.country=N(f.toString('utf8',e,e+2)),d.region=N(f.toString('utf8',e+2,e+5)),d.metro=f.readInt32BE(e+5),d.ll[0]=l.readInt32BE(u+12)/1e4,d.ll[1]=l.readInt32BE(u+16)/1e4,d.area=l.readUInt32BE(u+20),d.eu=N(f.toString('utf8',e+9,e+10)),d.timezone=N(f.toString('utf8',e+10,e+42)),d.city=N(f.toString('utf8',e+42,e+s))}return d}if(n===i)return null;n===i-1?r===n?n=i:i=n:o>e?i=r:a<e&&(n=r)}};function A(f){let u,c;const d={...F};if('function'==typeof arguments[0])s.series([i=>{s.series([r=>{e(P.cityNames,'r',(e,t)=>{u=t,r(e)})},e=>{r(u,(r,t)=>{c=t.size,d.locationBuffer=Buffer.alloc(c),e(r)})},e=>{t(u,d.locationBuffer,0,c,0,e)},e=>{n(u,e)},r=>{e(P.city,'r',(e,t)=>{u=t,r(e)})},e=>{r(u,(r,t)=>{c=t.size,e(r)})}],t=>{if(t){if('ENOENT'!==t.code&&'EBADF'!==t.code)throw t;e(P.country,'r',(e,t)=>{e?i(e):(u=t,r(u,(e,r)=>{c=r.size,d.recordSize=10,i()}))})}else i()})},()=>{d.mainBuffer=Buffer.alloc(c),s.series([e=>{t(u,d.mainBuffer,0,c,0,e)},e=>{n(u,e)}],e=>{e||(d.lastLine=c/d.recordSize-1,d.lastIP=d.mainBuffer.readUInt32BE(d.lastLine*d.recordSize+4),d.firstIP=d.mainBuffer.readUInt32BE(0),U=d),f(e)})}]);else{try{if(u=i(P.cityNames,'r'),c=o(u).size,0===c){const e=new Error('Empty file');throw e.code='EMPTY_FILE',e}U.locationBuffer=Buffer.alloc(c),a(u,U.locationBuffer,0,c,0),l(u),u=i(P.city,'r'),c=o(u).size}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;u=i(P.country,'r'),c=o(u).size,U.recordSize=10}U.mainBuffer=Buffer.alloc(c),a(u,U.mainBuffer,0,c,0),l(u),U.lastLine=c/U.recordSize-1,U.lastIP=U.mainBuffer.readUInt32BE(U.lastLine*U.recordSize+4),U.firstIP=U.mainBuffer.readUInt32BE(0)}}function W(f){let u,c;const d={...L};if('function'==typeof arguments[0])s.series([t=>{s.series([r=>{e(P.city6,'r',(e,t)=>{u=t,r(e)})},e=>{r(u,(r,t)=>{c=t.size,e(r)})}],n=>{if(n){if('ENOENT'!==n.code&&'EBADF'!==n.code)throw n;e(P.country6,'r',(e,n)=>{e?t(e):(u=n,r(u,(e,r)=>{c=r.size,d.recordSize=34,t()}))})}else t()})},()=>{d.mainBuffer=Buffer.alloc(c),s.series([e=>{t(u,d.mainBuffer,0,c,0,e)},e=>{n(u,e)}],e=>{e||(d.lastLine=c/d.recordSize-1,d.lastIP=T(d.mainBuffer,d.lastLine,d.recordSize,1),d.firstIP=T(d.mainBuffer,0,d.recordSize,0),D=d),f(e)})}]);else{try{if(u=i(P.city6,'r'),c=o(u).size,0===c){const e=new Error('Empty file');throw e.code='EMPTY_FILE',e}}catch(e){if('ENOENT'!==e.code&&'EBADF'!==e.code&&'EMPTY_FILE'!==e.code)throw e;u=i(P.country6,'r'),c=o(u).size,D.recordSize=34}D.mainBuffer=Buffer.alloc(c),a(u,D.mainBuffer,0,c,0),l(u),D.lastLine=c/D.recordSize-1,D.lastIP=T(D.mainBuffer,D.lastLine,D.recordSize,1),D.firstIP=T(D.mainBuffer,0,D.recordSize,0)}}module.exports={cmp:E,lookup:e=>{if(!e)return null;if('number'==typeof e)return w(e);if(4===c(e))return w(d(e));if(6===c(e)){const r=(e=>{const r=e.toUpperCase();return r.startsWith("0:0:0:0:0:FFFF:")?r.substring(15):r.startsWith("::FFFF:")?r.substring(7):null})(e);return r?w(d(r)):(e=>{const r=D.mainBuffer,t=D.recordSize,n=U.locationBuffer,i=U.locationRecordSize,o={range:[null,null],country:'',region:'',eu:'',timezone:'',city:'',ll:[null,null],metro:null,area:null};let a,l,f=0,u=D.lastLine,c=D.lastIP,s=D.firstIP;if(y(e,D.lastIP)>0||y(e,D.firstIP)<0)return null;for(;;){if(a=Math.round((u-f)/2)+f,c=T(r,a,t,0),s=T(r,a,t,1),y(c,e)<=0&&y(s,e)>=0){const e=a*t;if(34===t)o.country=N(r.toString('utf8',e+32,e+34));else if(l=r.readUInt32BE(e+32),-1>>>0>l){const t=l*i;o.country=N(n.toString('utf8',t,t+2)),o.region=N(n.toString('utf8',t+2,t+5)),o.metro=n.readInt32BE(t+5),o.ll[0]=r.readInt32BE(e+36)/1e4,o.ll[1]=r.readInt32BE(e+40)/1e4,o.area=r.readUInt32BE(e+44),o.eu=N(n.toString('utf8',t+9,t+10)),o.timezone=N(n.toString('utf8',t+10,t+42)),o.city=N(n.toString('utf8',t+42,t+i))}return o}if(f===u)return null;f===u-1?a===f?f=u:u=f:y(c,e)>0?u=a:y(s,e)<0&&(f=a)}})(B(e))}return null},pretty:e=>'string'==typeof e?e:'number'==typeof e?I(e):Array.isArray(e)?m(e):e,startWatchingDataUpdate:e=>{S.makeFsWatchFilter(z,p,6e4,()=>{s.series([e=>{A(e)},e=>{W(e)}],e)})},stopWatchingDataUpdate:()=>S.stopWatching(z),clear:()=>{U={...F},D={...L}},reloadDataSync:()=>{A(),W()},reloadData:e=>{s.series([e=>{A(e)},e=>{W(e)}],e)},version:g},A(),W();
|
package/dist/utils.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const t=module.exports={};t.aton4=t=>{const r=t.split('.');return(parseInt(r[0],10)<<24>>>0)+(parseInt(r[1],10)<<16>>>0)+(parseInt(r[2],10)<<8>>>0)+(parseInt(r[3],10)>>>0)},t.ntoa4=t=>(t>>>24&255)+'.'+(t>>>16&255)+'.'+(t>>>8&255)+'.'+(255&t),t.aton6=t=>{const r=(t=t.replace(/"/g,'').split(':')).length-1;let e;if(''===t[r]&&(t[r]=0),r<7)for(t.length=8,e=r;e>=0&&''!==t[e];e--)t[7-r+e]=t[e];for(e=0;e<8;e++)t[e]?t[e]=parseInt(t[e],16):t[e]=0;const n=[];for(e=0;e<4;e++)n.push((t[2*e]<<16)+t[2*e+1]>>>0);return n},t.ntoa6=t=>{let r='[';for(let e=0;e<t.length;e++)r+=(t[e]>>>16).toString(16)+':',r+=(65535&t[e]).toString(16)+':';return r=r.replace(/:$/,']').replace(/:0+/g,':').replace(/::+/,'::'),r},t.cmp=(r,e)=>'number'==typeof r&&'number'==typeof e?r<e?-1:r>e?1:0:r instanceof Array&&e instanceof Array?t.cmp6(r,e):null,t.cmp6=(t,r)=>{for(let e=0;e<2;e++){if(t[e]<r[e])return-1;if(t[e]>r[e])return 1}return 0},t.isPrivateIP=t=>{const r=t.toString();return r.startsWith('10.')||r.startsWith('192.168.')||r.startsWith('172.16.')||r.startsWith('127.')||r.startsWith('169.254.')||r.startsWith('fc00:')||r.startsWith('fe80:')};
|