@streamr/geoip-location 103.1.2-rc.0 → 103.2.0-experiment.0
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/dist/exports.cjs +287 -0
- package/dist/exports.cjs.map +1 -0
- package/dist/{src/GeoIpLocator.d.ts → exports.d.ts} +3 -2
- package/dist/exports.js +285 -0
- package/dist/exports.js.map +1 -0
- package/package.json +19 -12
- package/dist/src/GeoIpLocator.js +0 -98
- package/dist/src/GeoIpLocator.js.map +0 -1
- package/dist/src/downloadGeoIpDatabase.d.ts +0 -2
- package/dist/src/downloadGeoIpDatabase.js +0 -169
- package/dist/src/downloadGeoIpDatabase.js.map +0 -1
- package/dist/src/exports.d.ts +0 -1
- package/dist/src/exports.js +0 -6
- package/dist/src/exports.js.map +0 -1
- package/dist/src/tarHelper.d.ts +0 -2
- package/dist/src/tarHelper.js +0 -40
- package/dist/src/tarHelper.js.map +0 -1
package/dist/exports.cjs
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('@streamr/utils');
|
|
4
|
+
var LongTimeout = require('long-timeout');
|
|
5
|
+
var crypto = require('crypto');
|
|
6
|
+
var fs = require('fs');
|
|
7
|
+
var mmdbLib = require('mmdb-lib');
|
|
8
|
+
var stream = require('stream');
|
|
9
|
+
var tar = require('tar');
|
|
10
|
+
var NodePath = require('path');
|
|
11
|
+
var uuid = require('uuid');
|
|
12
|
+
|
|
13
|
+
const doExtractFileFromTarStream = (fileName, stream$1, downloadFolder) => {
|
|
14
|
+
return new Promise((resolve, reject) => {
|
|
15
|
+
try {
|
|
16
|
+
const nodeStream = stream.Readable.fromWeb(stream$1);
|
|
17
|
+
stream.pipeline(nodeStream, tar.extract({
|
|
18
|
+
cwd: downloadFolder,
|
|
19
|
+
filter: (entryPath) => NodePath.basename(entryPath) === fileName,
|
|
20
|
+
strip: 1
|
|
21
|
+
}), (err) => {
|
|
22
|
+
if (err) {
|
|
23
|
+
reject(new Error('Error extracting tarball to ' + downloadFolder + ', error: ' + err));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
resolve();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
reject(new Error('Failed to create nodejs Readable from web stream: ' + e));
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
const extractFileFromTarStream = async (fileName, stream, downloadFolder) => {
|
|
36
|
+
await doExtractFileFromTarStream(fileName, stream, downloadFolder);
|
|
37
|
+
if (!fs.existsSync(NodePath.join(downloadFolder, fileName))) {
|
|
38
|
+
throw new Error('File not found in tarball: ' + fileName);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const GEOIP_MIRROR_URL = 'https://raw.githubusercontent.com/GitSquared/node-geolite2-redist/master/redist/';
|
|
43
|
+
const DB_NAME = 'GeoLite2-City';
|
|
44
|
+
const TAR_SUFFFIX = '.tar.gz';
|
|
45
|
+
const DB_SUFFIX = '.mmdb';
|
|
46
|
+
const HASH_SUFFIX = '.mmdb.sha384';
|
|
47
|
+
const logger$1 = new utils.Logger('downloadGeoIpDatabase');
|
|
48
|
+
const downloadNewDb = async (url, dbFolder, remoteHash, abortSignal) => {
|
|
49
|
+
// make a unique name for the temporary download folder
|
|
50
|
+
// in case there are multiple downloads happening at the same time
|
|
51
|
+
const uniqueName = uuid.v4();
|
|
52
|
+
const downloadFolder = dbFolder + '.download' + uniqueName;
|
|
53
|
+
const dbFileName = DB_NAME + DB_SUFFIX;
|
|
54
|
+
const dbFileInDownloadFolder = downloadFolder + '/' + dbFileName;
|
|
55
|
+
const dbFileInDbFolder = dbFolder + dbFileName;
|
|
56
|
+
let response;
|
|
57
|
+
try {
|
|
58
|
+
logger$1.debug('Downloading GeoIP database from: ' + url);
|
|
59
|
+
response = await fetch(url, { keepalive: false, signal: abortSignal });
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
// Catching and re-throwing as async exception
|
|
63
|
+
// here is necessary, synch exceptions cannot be caught by the caller
|
|
64
|
+
throw new Error('Fetch error when downloading ' + url + ', error: ' + e);
|
|
65
|
+
}
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
throw new Error('HTTP error when downloading ' + url + ', status: ' + response.status);
|
|
68
|
+
}
|
|
69
|
+
// extract the tarball to a temporary folder
|
|
70
|
+
try {
|
|
71
|
+
fs.mkdirSync(downloadFolder, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
throw new Error('Error creating temporary folder ' + downloadFolder + ', error: ' + e);
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
await extractFileFromTarStream(dbFileName, response.body, downloadFolder);
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
try {
|
|
81
|
+
fs.rmSync(downloadFolder, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// ignore error when removing the temporary folder
|
|
85
|
+
}
|
|
86
|
+
throw e;
|
|
87
|
+
}
|
|
88
|
+
// check the hash of the extracted file
|
|
89
|
+
if (!isDbFileValid(dbFileInDownloadFolder, remoteHash)) {
|
|
90
|
+
try {
|
|
91
|
+
fs.rmSync(downloadFolder, { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// ignore error when removing the temporary folder
|
|
95
|
+
}
|
|
96
|
+
throw new Error('Downloaded database hash does not match the expected hash');
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
// move the extracted file to the correct location
|
|
100
|
+
fs.renameSync(dbFileInDownloadFolder, dbFileInDbFolder);
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
throw new Error('Error moving ' + dbFileInDownloadFolder + ' to ' + dbFileInDbFolder + ', error: ' + e);
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
try {
|
|
107
|
+
fs.rmSync(downloadFolder, { recursive: true });
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// ignore error when removing the temporary folder
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// set the db file permissions to rw only for the owner
|
|
114
|
+
try {
|
|
115
|
+
fs.chmodSync(dbFileInDbFolder, 0o600);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
throw new Error('Error setting permissions on ' + dbFileInDbFolder + ', error: ' + err);
|
|
119
|
+
}
|
|
120
|
+
logger$1.debug('Downloaded GeoIP database to: ' + dbFileInDbFolder);
|
|
121
|
+
};
|
|
122
|
+
const downloadRemoteHash = async (remoteHashUrl, abortSignal) => {
|
|
123
|
+
// download the hash of the latest GeoIP database using fetch as text and trim it
|
|
124
|
+
let response;
|
|
125
|
+
try {
|
|
126
|
+
logger$1.debug('Downloading GeoIP database hash from: ' + remoteHashUrl);
|
|
127
|
+
response = await fetch(remoteHashUrl, { signal: abortSignal });
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
// Catching and re-throwing as async exception
|
|
131
|
+
// here is necessary, synch exceptions cannot be caught by the caller
|
|
132
|
+
throw new Error('Fetch error when downloading ' + remoteHashUrl + ', error: ' + e);
|
|
133
|
+
}
|
|
134
|
+
if (!response.ok) {
|
|
135
|
+
throw new Error('HTTP error when downloading ' + remoteHashUrl + ', status: ' + response.status);
|
|
136
|
+
}
|
|
137
|
+
return (await response.text()).trim();
|
|
138
|
+
};
|
|
139
|
+
const isDbFileValid = (dbFile, remoteHash) => {
|
|
140
|
+
// check if the local db exists and calculate its hash
|
|
141
|
+
try {
|
|
142
|
+
const db = fs.readFileSync(dbFile);
|
|
143
|
+
const localHash = crypto.createHash('sha384').update(db).digest('hex');
|
|
144
|
+
// if the hashes are different, download the latest database
|
|
145
|
+
if (localHash !== remoteHash) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// if the local db does not exist, or some other exception occurres db is not considered valid
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
// returns a Reader if a new db was downloaded, or if the caller wants to force return a reader
|
|
158
|
+
// also if there was no need to download a new db
|
|
159
|
+
const downloadGeoIpDatabase = async (dbFolder, forceReturnReader, abortSignal, mirrorUrl) => {
|
|
160
|
+
// This will throw if the download folder is not readable
|
|
161
|
+
if (!fs.existsSync(dbFolder)) {
|
|
162
|
+
// This will throw if the download folder is not writable
|
|
163
|
+
fs.mkdirSync(dbFolder, { recursive: true });
|
|
164
|
+
}
|
|
165
|
+
if (!dbFolder.endsWith('/')) {
|
|
166
|
+
dbFolder += '/';
|
|
167
|
+
}
|
|
168
|
+
let geoIpMirrorUrl = GEOIP_MIRROR_URL;
|
|
169
|
+
if (mirrorUrl !== undefined) {
|
|
170
|
+
if (!mirrorUrl.endsWith('/')) {
|
|
171
|
+
mirrorUrl += '/';
|
|
172
|
+
}
|
|
173
|
+
geoIpMirrorUrl = mirrorUrl;
|
|
174
|
+
}
|
|
175
|
+
const remoteHashUrl = geoIpMirrorUrl + DB_NAME + HASH_SUFFIX;
|
|
176
|
+
const dbDownloadUrl = geoIpMirrorUrl + DB_NAME + TAR_SUFFFIX;
|
|
177
|
+
const dbFileInDbFolder = dbFolder + DB_NAME + DB_SUFFIX;
|
|
178
|
+
const remoteHash = await downloadRemoteHash(remoteHashUrl, abortSignal);
|
|
179
|
+
const dbValid = isDbFileValid(dbFileInDbFolder, remoteHash);
|
|
180
|
+
if (dbValid === false) {
|
|
181
|
+
await downloadNewDb(dbDownloadUrl, dbFolder, remoteHash, abortSignal);
|
|
182
|
+
// return new reader if db was downloaded
|
|
183
|
+
return new mmdbLib.Reader(fs.readFileSync(dbFileInDbFolder));
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
logger$1.debug('The hash of the local GeoIP database matches the remote hash, no need to download a new database');
|
|
187
|
+
}
|
|
188
|
+
if (forceReturnReader) {
|
|
189
|
+
// return reader also for old db the caller wants it
|
|
190
|
+
return new mmdbLib.Reader(fs.readFileSync(dbFileInDbFolder));
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
// return undefined if the db is already up to date
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const logger = new utils.Logger('GeoIpLocator');
|
|
199
|
+
// 30 days in milliseconds
|
|
200
|
+
const DEFAULT_DB_CHECK_INTERVAL = 30 * 24 * 60 * 60 * 1000;
|
|
201
|
+
// 24 hours in milliseconds
|
|
202
|
+
const DEFAULT_DB_CHECK_ERROR_INTERVAL = 24 * 60 * 60 * 1000;
|
|
203
|
+
class GeoIpLocator {
|
|
204
|
+
abortController;
|
|
205
|
+
geoIpDatabaseFolder;
|
|
206
|
+
dbCheckInterval;
|
|
207
|
+
dbCheckErrorInterval;
|
|
208
|
+
mirrorUrl;
|
|
209
|
+
reader;
|
|
210
|
+
dbCheckTimeout;
|
|
211
|
+
constructor(geoIpDatabaseFolder, dbCheckInterval = DEFAULT_DB_CHECK_INTERVAL, dbCheckErrorInterval = DEFAULT_DB_CHECK_ERROR_INTERVAL, mirrorUrl) {
|
|
212
|
+
this.abortController = new AbortController();
|
|
213
|
+
this.dbCheckInterval = dbCheckInterval;
|
|
214
|
+
this.dbCheckErrorInterval = dbCheckErrorInterval;
|
|
215
|
+
if (!geoIpDatabaseFolder.endsWith('/')) {
|
|
216
|
+
geoIpDatabaseFolder += '/';
|
|
217
|
+
}
|
|
218
|
+
this.geoIpDatabaseFolder = utils.filePathToNodeFormat(geoIpDatabaseFolder);
|
|
219
|
+
this.mirrorUrl = mirrorUrl;
|
|
220
|
+
}
|
|
221
|
+
checkDatabase = async () => {
|
|
222
|
+
if (this.reader === undefined) {
|
|
223
|
+
// if we do not have a reader, create a new one in any case
|
|
224
|
+
this.reader = await downloadGeoIpDatabase(this.geoIpDatabaseFolder, true, this.abortController.signal, this.mirrorUrl);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
// if we already have a reader, create a new one only if db has changed
|
|
228
|
+
const newReader = await downloadGeoIpDatabase(this.geoIpDatabaseFolder, false, this.abortController.signal, this.mirrorUrl);
|
|
229
|
+
if (newReader !== undefined) {
|
|
230
|
+
this.reader = newReader;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
scheduleCheck = async (timeout) => {
|
|
235
|
+
if (this.abortController.signal.aborted) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
this.dbCheckTimeout = LongTimeout.setTimeout(async () => {
|
|
239
|
+
try {
|
|
240
|
+
await this.checkDatabase();
|
|
241
|
+
this.scheduleCheck(this.dbCheckInterval);
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
logger.warn('GeoIpLocator: GeoIP database check failed', { err });
|
|
245
|
+
this.scheduleCheck(this.dbCheckErrorInterval);
|
|
246
|
+
}
|
|
247
|
+
}, timeout);
|
|
248
|
+
};
|
|
249
|
+
async start() {
|
|
250
|
+
if (this.dbCheckTimeout !== undefined) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
await this.checkDatabase();
|
|
254
|
+
this.scheduleCheck(this.dbCheckInterval);
|
|
255
|
+
}
|
|
256
|
+
stop() {
|
|
257
|
+
if (this.dbCheckTimeout !== undefined) {
|
|
258
|
+
LongTimeout.clearTimeout(this.dbCheckTimeout);
|
|
259
|
+
}
|
|
260
|
+
this.abortController.abort();
|
|
261
|
+
}
|
|
262
|
+
lookup(ip) {
|
|
263
|
+
if (this.reader === undefined) {
|
|
264
|
+
logger.warn('GeoIpLocator: lookup called before database is ready (maybe start() was not called?');
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
// If ip is falsy, the library will crash
|
|
268
|
+
// this might happen despite the ts typings because the ip address
|
|
269
|
+
// comes from the ws server socket and is not under our control
|
|
270
|
+
if (!ip) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
const result = this.reader.get(ip);
|
|
274
|
+
if (!result?.location?.latitude || !result.location.longitude) {
|
|
275
|
+
return undefined;
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
return {
|
|
279
|
+
latitude: result.location.latitude,
|
|
280
|
+
longitude: result.location.longitude
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
exports.GeoIpLocator = GeoIpLocator;
|
|
287
|
+
//# sourceMappingURL=exports.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports.cjs","sources":["src/tarHelper.js","src/downloadGeoIpDatabase.js","src/GeoIpLocator.js"],"sourcesContent":["import { Readable, pipeline } from 'stream';\nimport { extract } from 'tar';\nimport NodePath from 'path'; // use NodePath to avoid conflict with other 'path' symbols\nimport fs from 'fs';\nconst doExtractFileFromTarStream = (fileName, stream, downloadFolder) => {\n return new Promise((resolve, reject) => {\n try {\n const nodeStream = Readable.fromWeb(stream);\n pipeline(nodeStream, extract({\n cwd: downloadFolder,\n filter: (entryPath) => NodePath.basename(entryPath) === fileName,\n strip: 1\n }), (err) => {\n if (err) {\n reject(new Error('Error extracting tarball to ' + downloadFolder + ', error: ' + err));\n }\n else {\n resolve();\n }\n });\n }\n catch (e) {\n reject(new Error('Failed to create nodejs Readable from web stream: ' + e));\n }\n });\n};\nexport const extractFileFromTarStream = async (fileName, stream, downloadFolder) => {\n await doExtractFileFromTarStream(fileName, stream, downloadFolder);\n if (!fs.existsSync(NodePath.join(downloadFolder, fileName))) {\n throw new Error('File not found in tarball: ' + fileName);\n }\n};\n//# sourceMappingURL=tarHelper.js.map","import crypto from 'crypto';\nimport fs from 'fs';\nimport { Reader } from 'mmdb-lib';\nimport { extractFileFromTarStream } from './tarHelper';\nimport { v4 } from 'uuid';\nimport { Logger } from '@streamr/utils';\nconst GEOIP_MIRROR_URL = 'https://raw.githubusercontent.com/GitSquared/node-geolite2-redist/master/redist/';\nconst DB_NAME = 'GeoLite2-City';\nconst TAR_SUFFFIX = '.tar.gz';\nconst DB_SUFFIX = '.mmdb';\nconst HASH_SUFFIX = '.mmdb.sha384';\nconst logger = new Logger('downloadGeoIpDatabase');\nconst downloadNewDb = async (url, dbFolder, remoteHash, abortSignal) => {\n // make a unique name for the temporary download folder\n // in case there are multiple downloads happening at the same time\n const uniqueName = v4();\n const downloadFolder = dbFolder + '.download' + uniqueName;\n const dbFileName = DB_NAME + DB_SUFFIX;\n const dbFileInDownloadFolder = downloadFolder + '/' + dbFileName;\n const dbFileInDbFolder = dbFolder + dbFileName;\n let response;\n try {\n logger.debug('Downloading GeoIP database from: ' + url);\n response = await fetch(url, { keepalive: false, signal: abortSignal });\n }\n catch (e) {\n // Catching and re-throwing as async exception \n // here is necessary, synch exceptions cannot be caught by the caller\n throw new Error('Fetch error when downloading ' + url + ', error: ' + e);\n }\n if (!response.ok) {\n throw new Error('HTTP error when downloading ' + url + ', status: ' + response.status);\n }\n // extract the tarball to a temporary folder\n try {\n fs.mkdirSync(downloadFolder, { recursive: true });\n }\n catch (e) {\n throw new Error('Error creating temporary folder ' + downloadFolder + ', error: ' + e);\n }\n try {\n await extractFileFromTarStream(dbFileName, response.body, downloadFolder);\n }\n catch (e) {\n try {\n fs.rmSync(downloadFolder, { recursive: true });\n }\n catch {\n // ignore error when removing the temporary folder\n }\n throw e;\n }\n // check the hash of the extracted file\n if (!isDbFileValid(dbFileInDownloadFolder, remoteHash)) {\n try {\n fs.rmSync(downloadFolder, { recursive: true });\n }\n catch {\n // ignore error when removing the temporary folder\n }\n throw new Error('Downloaded database hash does not match the expected hash');\n }\n try {\n // move the extracted file to the correct location\n fs.renameSync(dbFileInDownloadFolder, dbFileInDbFolder);\n }\n catch (e) {\n throw new Error('Error moving ' + dbFileInDownloadFolder + ' to ' + dbFileInDbFolder + ', error: ' + e);\n }\n finally {\n try {\n fs.rmSync(downloadFolder, { recursive: true });\n }\n catch {\n // ignore error when removing the temporary folder\n }\n }\n // set the db file permissions to rw only for the owner\n try {\n fs.chmodSync(dbFileInDbFolder, 0o600);\n }\n catch (err) {\n throw new Error('Error setting permissions on ' + dbFileInDbFolder + ', error: ' + err);\n }\n logger.debug('Downloaded GeoIP database to: ' + dbFileInDbFolder);\n};\nconst downloadRemoteHash = async (remoteHashUrl, abortSignal) => {\n // download the hash of the latest GeoIP database using fetch as text and trim it\n let response;\n try {\n logger.debug('Downloading GeoIP database hash from: ' + remoteHashUrl);\n response = await fetch(remoteHashUrl, { signal: abortSignal });\n }\n catch (e) {\n // Catching and re-throwing as async exception \n // here is necessary, synch exceptions cannot be caught by the caller\n throw new Error('Fetch error when downloading ' + remoteHashUrl + ', error: ' + e);\n }\n if (!response.ok) {\n throw new Error('HTTP error when downloading ' + remoteHashUrl + ', status: ' + response.status);\n }\n return (await response.text()).trim();\n};\nconst isDbFileValid = (dbFile, remoteHash) => {\n // check if the local db exists and calculate its hash\n try {\n const db = fs.readFileSync(dbFile);\n const localHash = crypto.createHash('sha384').update(db).digest('hex');\n // if the hashes are different, download the latest database\n if (localHash !== remoteHash) {\n return false;\n }\n else {\n return true;\n }\n }\n catch {\n // if the local db does not exist, or some other exception occurres db is not considered valid\n return false;\n }\n};\n// returns a Reader if a new db was downloaded, or if the caller wants to force return a reader\n// also if there was no need to download a new db\nexport const downloadGeoIpDatabase = async (dbFolder, forceReturnReader, abortSignal, mirrorUrl) => {\n // This will throw if the download folder is not readable\n if (!fs.existsSync(dbFolder)) {\n // This will throw if the download folder is not writable\n fs.mkdirSync(dbFolder, { recursive: true });\n }\n if (!dbFolder.endsWith('/')) {\n dbFolder += '/';\n }\n let geoIpMirrorUrl = GEOIP_MIRROR_URL;\n if (mirrorUrl !== undefined) {\n if (!mirrorUrl.endsWith('/')) {\n mirrorUrl += '/';\n }\n geoIpMirrorUrl = mirrorUrl;\n }\n const remoteHashUrl = geoIpMirrorUrl + DB_NAME + HASH_SUFFIX;\n const dbDownloadUrl = geoIpMirrorUrl + DB_NAME + TAR_SUFFFIX;\n const dbFileInDbFolder = dbFolder + DB_NAME + DB_SUFFIX;\n const remoteHash = await downloadRemoteHash(remoteHashUrl, abortSignal);\n const dbValid = isDbFileValid(dbFileInDbFolder, remoteHash);\n if (dbValid === false) {\n await downloadNewDb(dbDownloadUrl, dbFolder, remoteHash, abortSignal);\n // return new reader if db was downloaded\n return new Reader(fs.readFileSync(dbFileInDbFolder));\n }\n else {\n logger.debug('The hash of the local GeoIP database matches the remote hash, no need to download a new database');\n }\n if (forceReturnReader) {\n // return reader also for old db the caller wants it\n return new Reader(fs.readFileSync(dbFileInDbFolder));\n }\n else {\n // return undefined if the db is already up to date\n return undefined;\n }\n};\n//# sourceMappingURL=downloadGeoIpDatabase.js.map","import { Logger, filePathToNodeFormat } from '@streamr/utils';\nimport LongTimeout from 'long-timeout';\nimport { downloadGeoIpDatabase } from './downloadGeoIpDatabase';\nconst logger = new Logger('GeoIpLocator');\n// 30 days in milliseconds\nconst DEFAULT_DB_CHECK_INTERVAL = 30 * 24 * 60 * 60 * 1000;\n// 24 hours in milliseconds\nconst DEFAULT_DB_CHECK_ERROR_INTERVAL = 24 * 60 * 60 * 1000;\nexport class GeoIpLocator {\n abortController;\n geoIpDatabaseFolder;\n dbCheckInterval;\n dbCheckErrorInterval;\n mirrorUrl;\n reader;\n dbCheckTimeout;\n constructor(geoIpDatabaseFolder, dbCheckInterval = DEFAULT_DB_CHECK_INTERVAL, dbCheckErrorInterval = DEFAULT_DB_CHECK_ERROR_INTERVAL, mirrorUrl) {\n this.abortController = new AbortController();\n this.dbCheckInterval = dbCheckInterval;\n this.dbCheckErrorInterval = dbCheckErrorInterval;\n if (!geoIpDatabaseFolder.endsWith('/')) {\n geoIpDatabaseFolder += '/';\n }\n this.geoIpDatabaseFolder = filePathToNodeFormat(geoIpDatabaseFolder);\n this.mirrorUrl = mirrorUrl;\n }\n checkDatabase = async () => {\n if (this.reader === undefined) {\n // if we do not have a reader, create a new one in any case\n this.reader = await downloadGeoIpDatabase(this.geoIpDatabaseFolder, true, this.abortController.signal, this.mirrorUrl);\n }\n else {\n // if we already have a reader, create a new one only if db has changed\n const newReader = await downloadGeoIpDatabase(this.geoIpDatabaseFolder, false, this.abortController.signal, this.mirrorUrl);\n if (newReader !== undefined) {\n this.reader = newReader;\n }\n }\n };\n scheduleCheck = async (timeout) => {\n if (this.abortController.signal.aborted) {\n return;\n }\n this.dbCheckTimeout = LongTimeout.setTimeout(async () => {\n try {\n await this.checkDatabase();\n this.scheduleCheck(this.dbCheckInterval);\n }\n catch (err) {\n logger.warn('GeoIpLocator: GeoIP database check failed', { err });\n this.scheduleCheck(this.dbCheckErrorInterval);\n }\n }, timeout);\n };\n async start() {\n if (this.dbCheckTimeout !== undefined) {\n return;\n }\n await this.checkDatabase();\n this.scheduleCheck(this.dbCheckInterval);\n }\n stop() {\n if (this.dbCheckTimeout !== undefined) {\n LongTimeout.clearTimeout(this.dbCheckTimeout);\n }\n this.abortController.abort();\n }\n lookup(ip) {\n if (this.reader === undefined) {\n logger.warn('GeoIpLocator: lookup called before database is ready (maybe start() was not called?');\n return undefined;\n }\n // If ip is falsy, the library will crash\n // this might happen despite the ts typings because the ip address \n // comes from the ws server socket and is not under our control\n if (!ip) {\n return undefined;\n }\n const result = this.reader.get(ip);\n if (!result?.location?.latitude || !result.location.longitude) {\n return undefined;\n }\n else {\n return {\n latitude: result.location.latitude,\n longitude: result.location.longitude\n };\n }\n }\n}\n//# sourceMappingURL=GeoIpLocator.js.map"],"names":["stream","Readable","pipeline","extract","logger","Logger","v4","Reader","filePathToNodeFormat"],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ interface GeoIpLookupResult {
|
|
|
2
2
|
latitude: number;
|
|
3
3
|
longitude: number;
|
|
4
4
|
}
|
|
5
|
-
|
|
5
|
+
declare class GeoIpLocator {
|
|
6
6
|
private abortController;
|
|
7
7
|
private readonly geoIpDatabaseFolder;
|
|
8
8
|
private readonly dbCheckInterval;
|
|
@@ -17,4 +17,5 @@ export declare class GeoIpLocator {
|
|
|
17
17
|
stop(): void;
|
|
18
18
|
lookup(ip: string): GeoIpLookupResult | undefined;
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
export { GeoIpLocator };
|
package/dist/exports.js
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { Logger, filePathToNodeFormat } from '@streamr/utils';
|
|
2
|
+
import LongTimeout from 'long-timeout';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { Reader } from 'mmdb-lib';
|
|
6
|
+
import { Readable, pipeline } from 'stream';
|
|
7
|
+
import { extract } from 'tar';
|
|
8
|
+
import NodePath from 'path';
|
|
9
|
+
import { v4 } from 'uuid';
|
|
10
|
+
|
|
11
|
+
const doExtractFileFromTarStream = (fileName, stream, downloadFolder) => {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
try {
|
|
14
|
+
const nodeStream = Readable.fromWeb(stream);
|
|
15
|
+
pipeline(nodeStream, extract({
|
|
16
|
+
cwd: downloadFolder,
|
|
17
|
+
filter: (entryPath) => NodePath.basename(entryPath) === fileName,
|
|
18
|
+
strip: 1
|
|
19
|
+
}), (err) => {
|
|
20
|
+
if (err) {
|
|
21
|
+
reject(new Error('Error extracting tarball to ' + downloadFolder + ', error: ' + err));
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
resolve();
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
reject(new Error('Failed to create nodejs Readable from web stream: ' + e));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
const extractFileFromTarStream = async (fileName, stream, downloadFolder) => {
|
|
34
|
+
await doExtractFileFromTarStream(fileName, stream, downloadFolder);
|
|
35
|
+
if (!fs.existsSync(NodePath.join(downloadFolder, fileName))) {
|
|
36
|
+
throw new Error('File not found in tarball: ' + fileName);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const GEOIP_MIRROR_URL = 'https://raw.githubusercontent.com/GitSquared/node-geolite2-redist/master/redist/';
|
|
41
|
+
const DB_NAME = 'GeoLite2-City';
|
|
42
|
+
const TAR_SUFFFIX = '.tar.gz';
|
|
43
|
+
const DB_SUFFIX = '.mmdb';
|
|
44
|
+
const HASH_SUFFIX = '.mmdb.sha384';
|
|
45
|
+
const logger$1 = new Logger('downloadGeoIpDatabase');
|
|
46
|
+
const downloadNewDb = async (url, dbFolder, remoteHash, abortSignal) => {
|
|
47
|
+
// make a unique name for the temporary download folder
|
|
48
|
+
// in case there are multiple downloads happening at the same time
|
|
49
|
+
const uniqueName = v4();
|
|
50
|
+
const downloadFolder = dbFolder + '.download' + uniqueName;
|
|
51
|
+
const dbFileName = DB_NAME + DB_SUFFIX;
|
|
52
|
+
const dbFileInDownloadFolder = downloadFolder + '/' + dbFileName;
|
|
53
|
+
const dbFileInDbFolder = dbFolder + dbFileName;
|
|
54
|
+
let response;
|
|
55
|
+
try {
|
|
56
|
+
logger$1.debug('Downloading GeoIP database from: ' + url);
|
|
57
|
+
response = await fetch(url, { keepalive: false, signal: abortSignal });
|
|
58
|
+
}
|
|
59
|
+
catch (e) {
|
|
60
|
+
// Catching and re-throwing as async exception
|
|
61
|
+
// here is necessary, synch exceptions cannot be caught by the caller
|
|
62
|
+
throw new Error('Fetch error when downloading ' + url + ', error: ' + e);
|
|
63
|
+
}
|
|
64
|
+
if (!response.ok) {
|
|
65
|
+
throw new Error('HTTP error when downloading ' + url + ', status: ' + response.status);
|
|
66
|
+
}
|
|
67
|
+
// extract the tarball to a temporary folder
|
|
68
|
+
try {
|
|
69
|
+
fs.mkdirSync(downloadFolder, { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
catch (e) {
|
|
72
|
+
throw new Error('Error creating temporary folder ' + downloadFolder + ', error: ' + e);
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
await extractFileFromTarStream(dbFileName, response.body, downloadFolder);
|
|
76
|
+
}
|
|
77
|
+
catch (e) {
|
|
78
|
+
try {
|
|
79
|
+
fs.rmSync(downloadFolder, { recursive: true });
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// ignore error when removing the temporary folder
|
|
83
|
+
}
|
|
84
|
+
throw e;
|
|
85
|
+
}
|
|
86
|
+
// check the hash of the extracted file
|
|
87
|
+
if (!isDbFileValid(dbFileInDownloadFolder, remoteHash)) {
|
|
88
|
+
try {
|
|
89
|
+
fs.rmSync(downloadFolder, { recursive: true });
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// ignore error when removing the temporary folder
|
|
93
|
+
}
|
|
94
|
+
throw new Error('Downloaded database hash does not match the expected hash');
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
// move the extracted file to the correct location
|
|
98
|
+
fs.renameSync(dbFileInDownloadFolder, dbFileInDbFolder);
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
throw new Error('Error moving ' + dbFileInDownloadFolder + ' to ' + dbFileInDbFolder + ', error: ' + e);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
try {
|
|
105
|
+
fs.rmSync(downloadFolder, { recursive: true });
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// ignore error when removing the temporary folder
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// set the db file permissions to rw only for the owner
|
|
112
|
+
try {
|
|
113
|
+
fs.chmodSync(dbFileInDbFolder, 0o600);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
throw new Error('Error setting permissions on ' + dbFileInDbFolder + ', error: ' + err);
|
|
117
|
+
}
|
|
118
|
+
logger$1.debug('Downloaded GeoIP database to: ' + dbFileInDbFolder);
|
|
119
|
+
};
|
|
120
|
+
const downloadRemoteHash = async (remoteHashUrl, abortSignal) => {
|
|
121
|
+
// download the hash of the latest GeoIP database using fetch as text and trim it
|
|
122
|
+
let response;
|
|
123
|
+
try {
|
|
124
|
+
logger$1.debug('Downloading GeoIP database hash from: ' + remoteHashUrl);
|
|
125
|
+
response = await fetch(remoteHashUrl, { signal: abortSignal });
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
// Catching and re-throwing as async exception
|
|
129
|
+
// here is necessary, synch exceptions cannot be caught by the caller
|
|
130
|
+
throw new Error('Fetch error when downloading ' + remoteHashUrl + ', error: ' + e);
|
|
131
|
+
}
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
throw new Error('HTTP error when downloading ' + remoteHashUrl + ', status: ' + response.status);
|
|
134
|
+
}
|
|
135
|
+
return (await response.text()).trim();
|
|
136
|
+
};
|
|
137
|
+
const isDbFileValid = (dbFile, remoteHash) => {
|
|
138
|
+
// check if the local db exists and calculate its hash
|
|
139
|
+
try {
|
|
140
|
+
const db = fs.readFileSync(dbFile);
|
|
141
|
+
const localHash = crypto.createHash('sha384').update(db).digest('hex');
|
|
142
|
+
// if the hashes are different, download the latest database
|
|
143
|
+
if (localHash !== remoteHash) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// if the local db does not exist, or some other exception occurres db is not considered valid
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
// returns a Reader if a new db was downloaded, or if the caller wants to force return a reader
|
|
156
|
+
// also if there was no need to download a new db
|
|
157
|
+
const downloadGeoIpDatabase = async (dbFolder, forceReturnReader, abortSignal, mirrorUrl) => {
|
|
158
|
+
// This will throw if the download folder is not readable
|
|
159
|
+
if (!fs.existsSync(dbFolder)) {
|
|
160
|
+
// This will throw if the download folder is not writable
|
|
161
|
+
fs.mkdirSync(dbFolder, { recursive: true });
|
|
162
|
+
}
|
|
163
|
+
if (!dbFolder.endsWith('/')) {
|
|
164
|
+
dbFolder += '/';
|
|
165
|
+
}
|
|
166
|
+
let geoIpMirrorUrl = GEOIP_MIRROR_URL;
|
|
167
|
+
if (mirrorUrl !== undefined) {
|
|
168
|
+
if (!mirrorUrl.endsWith('/')) {
|
|
169
|
+
mirrorUrl += '/';
|
|
170
|
+
}
|
|
171
|
+
geoIpMirrorUrl = mirrorUrl;
|
|
172
|
+
}
|
|
173
|
+
const remoteHashUrl = geoIpMirrorUrl + DB_NAME + HASH_SUFFIX;
|
|
174
|
+
const dbDownloadUrl = geoIpMirrorUrl + DB_NAME + TAR_SUFFFIX;
|
|
175
|
+
const dbFileInDbFolder = dbFolder + DB_NAME + DB_SUFFIX;
|
|
176
|
+
const remoteHash = await downloadRemoteHash(remoteHashUrl, abortSignal);
|
|
177
|
+
const dbValid = isDbFileValid(dbFileInDbFolder, remoteHash);
|
|
178
|
+
if (dbValid === false) {
|
|
179
|
+
await downloadNewDb(dbDownloadUrl, dbFolder, remoteHash, abortSignal);
|
|
180
|
+
// return new reader if db was downloaded
|
|
181
|
+
return new Reader(fs.readFileSync(dbFileInDbFolder));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
logger$1.debug('The hash of the local GeoIP database matches the remote hash, no need to download a new database');
|
|
185
|
+
}
|
|
186
|
+
if (forceReturnReader) {
|
|
187
|
+
// return reader also for old db the caller wants it
|
|
188
|
+
return new Reader(fs.readFileSync(dbFileInDbFolder));
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
// return undefined if the db is already up to date
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const logger = new Logger('GeoIpLocator');
|
|
197
|
+
// 30 days in milliseconds
|
|
198
|
+
const DEFAULT_DB_CHECK_INTERVAL = 30 * 24 * 60 * 60 * 1000;
|
|
199
|
+
// 24 hours in milliseconds
|
|
200
|
+
const DEFAULT_DB_CHECK_ERROR_INTERVAL = 24 * 60 * 60 * 1000;
|
|
201
|
+
class GeoIpLocator {
|
|
202
|
+
abortController;
|
|
203
|
+
geoIpDatabaseFolder;
|
|
204
|
+
dbCheckInterval;
|
|
205
|
+
dbCheckErrorInterval;
|
|
206
|
+
mirrorUrl;
|
|
207
|
+
reader;
|
|
208
|
+
dbCheckTimeout;
|
|
209
|
+
constructor(geoIpDatabaseFolder, dbCheckInterval = DEFAULT_DB_CHECK_INTERVAL, dbCheckErrorInterval = DEFAULT_DB_CHECK_ERROR_INTERVAL, mirrorUrl) {
|
|
210
|
+
this.abortController = new AbortController();
|
|
211
|
+
this.dbCheckInterval = dbCheckInterval;
|
|
212
|
+
this.dbCheckErrorInterval = dbCheckErrorInterval;
|
|
213
|
+
if (!geoIpDatabaseFolder.endsWith('/')) {
|
|
214
|
+
geoIpDatabaseFolder += '/';
|
|
215
|
+
}
|
|
216
|
+
this.geoIpDatabaseFolder = filePathToNodeFormat(geoIpDatabaseFolder);
|
|
217
|
+
this.mirrorUrl = mirrorUrl;
|
|
218
|
+
}
|
|
219
|
+
checkDatabase = async () => {
|
|
220
|
+
if (this.reader === undefined) {
|
|
221
|
+
// if we do not have a reader, create a new one in any case
|
|
222
|
+
this.reader = await downloadGeoIpDatabase(this.geoIpDatabaseFolder, true, this.abortController.signal, this.mirrorUrl);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
// if we already have a reader, create a new one only if db has changed
|
|
226
|
+
const newReader = await downloadGeoIpDatabase(this.geoIpDatabaseFolder, false, this.abortController.signal, this.mirrorUrl);
|
|
227
|
+
if (newReader !== undefined) {
|
|
228
|
+
this.reader = newReader;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
scheduleCheck = async (timeout) => {
|
|
233
|
+
if (this.abortController.signal.aborted) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
this.dbCheckTimeout = LongTimeout.setTimeout(async () => {
|
|
237
|
+
try {
|
|
238
|
+
await this.checkDatabase();
|
|
239
|
+
this.scheduleCheck(this.dbCheckInterval);
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
logger.warn('GeoIpLocator: GeoIP database check failed', { err });
|
|
243
|
+
this.scheduleCheck(this.dbCheckErrorInterval);
|
|
244
|
+
}
|
|
245
|
+
}, timeout);
|
|
246
|
+
};
|
|
247
|
+
async start() {
|
|
248
|
+
if (this.dbCheckTimeout !== undefined) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
await this.checkDatabase();
|
|
252
|
+
this.scheduleCheck(this.dbCheckInterval);
|
|
253
|
+
}
|
|
254
|
+
stop() {
|
|
255
|
+
if (this.dbCheckTimeout !== undefined) {
|
|
256
|
+
LongTimeout.clearTimeout(this.dbCheckTimeout);
|
|
257
|
+
}
|
|
258
|
+
this.abortController.abort();
|
|
259
|
+
}
|
|
260
|
+
lookup(ip) {
|
|
261
|
+
if (this.reader === undefined) {
|
|
262
|
+
logger.warn('GeoIpLocator: lookup called before database is ready (maybe start() was not called?');
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
// If ip is falsy, the library will crash
|
|
266
|
+
// this might happen despite the ts typings because the ip address
|
|
267
|
+
// comes from the ws server socket and is not under our control
|
|
268
|
+
if (!ip) {
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
const result = this.reader.get(ip);
|
|
272
|
+
if (!result?.location?.latitude || !result.location.longitude) {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
return {
|
|
277
|
+
latitude: result.location.latitude,
|
|
278
|
+
longitude: result.location.longitude
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export { GeoIpLocator };
|
|
285
|
+
//# sourceMappingURL=exports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exports.js","sources":["src/tarHelper.js","src/downloadGeoIpDatabase.js","src/GeoIpLocator.js"],"sourcesContent":["import { Readable, pipeline } from 'stream';\nimport { extract } from 'tar';\nimport NodePath from 'path'; // use NodePath to avoid conflict with other 'path' symbols\nimport fs from 'fs';\nconst doExtractFileFromTarStream = (fileName, stream, downloadFolder) => {\n return new Promise((resolve, reject) => {\n try {\n const nodeStream = Readable.fromWeb(stream);\n pipeline(nodeStream, extract({\n cwd: downloadFolder,\n filter: (entryPath) => NodePath.basename(entryPath) === fileName,\n strip: 1\n }), (err) => {\n if (err) {\n reject(new Error('Error extracting tarball to ' + downloadFolder + ', error: ' + err));\n }\n else {\n resolve();\n }\n });\n }\n catch (e) {\n reject(new Error('Failed to create nodejs Readable from web stream: ' + e));\n }\n });\n};\nexport const extractFileFromTarStream = async (fileName, stream, downloadFolder) => {\n await doExtractFileFromTarStream(fileName, stream, downloadFolder);\n if (!fs.existsSync(NodePath.join(downloadFolder, fileName))) {\n throw new Error('File not found in tarball: ' + fileName);\n }\n};\n//# sourceMappingURL=tarHelper.js.map","import crypto from 'crypto';\nimport fs from 'fs';\nimport { Reader } from 'mmdb-lib';\nimport { extractFileFromTarStream } from './tarHelper';\nimport { v4 } from 'uuid';\nimport { Logger } from '@streamr/utils';\nconst GEOIP_MIRROR_URL = 'https://raw.githubusercontent.com/GitSquared/node-geolite2-redist/master/redist/';\nconst DB_NAME = 'GeoLite2-City';\nconst TAR_SUFFFIX = '.tar.gz';\nconst DB_SUFFIX = '.mmdb';\nconst HASH_SUFFIX = '.mmdb.sha384';\nconst logger = new Logger('downloadGeoIpDatabase');\nconst downloadNewDb = async (url, dbFolder, remoteHash, abortSignal) => {\n // make a unique name for the temporary download folder\n // in case there are multiple downloads happening at the same time\n const uniqueName = v4();\n const downloadFolder = dbFolder + '.download' + uniqueName;\n const dbFileName = DB_NAME + DB_SUFFIX;\n const dbFileInDownloadFolder = downloadFolder + '/' + dbFileName;\n const dbFileInDbFolder = dbFolder + dbFileName;\n let response;\n try {\n logger.debug('Downloading GeoIP database from: ' + url);\n response = await fetch(url, { keepalive: false, signal: abortSignal });\n }\n catch (e) {\n // Catching and re-throwing as async exception \n // here is necessary, synch exceptions cannot be caught by the caller\n throw new Error('Fetch error when downloading ' + url + ', error: ' + e);\n }\n if (!response.ok) {\n throw new Error('HTTP error when downloading ' + url + ', status: ' + response.status);\n }\n // extract the tarball to a temporary folder\n try {\n fs.mkdirSync(downloadFolder, { recursive: true });\n }\n catch (e) {\n throw new Error('Error creating temporary folder ' + downloadFolder + ', error: ' + e);\n }\n try {\n await extractFileFromTarStream(dbFileName, response.body, downloadFolder);\n }\n catch (e) {\n try {\n fs.rmSync(downloadFolder, { recursive: true });\n }\n catch {\n // ignore error when removing the temporary folder\n }\n throw e;\n }\n // check the hash of the extracted file\n if (!isDbFileValid(dbFileInDownloadFolder, remoteHash)) {\n try {\n fs.rmSync(downloadFolder, { recursive: true });\n }\n catch {\n // ignore error when removing the temporary folder\n }\n throw new Error('Downloaded database hash does not match the expected hash');\n }\n try {\n // move the extracted file to the correct location\n fs.renameSync(dbFileInDownloadFolder, dbFileInDbFolder);\n }\n catch (e) {\n throw new Error('Error moving ' + dbFileInDownloadFolder + ' to ' + dbFileInDbFolder + ', error: ' + e);\n }\n finally {\n try {\n fs.rmSync(downloadFolder, { recursive: true });\n }\n catch {\n // ignore error when removing the temporary folder\n }\n }\n // set the db file permissions to rw only for the owner\n try {\n fs.chmodSync(dbFileInDbFolder, 0o600);\n }\n catch (err) {\n throw new Error('Error setting permissions on ' + dbFileInDbFolder + ', error: ' + err);\n }\n logger.debug('Downloaded GeoIP database to: ' + dbFileInDbFolder);\n};\nconst downloadRemoteHash = async (remoteHashUrl, abortSignal) => {\n // download the hash of the latest GeoIP database using fetch as text and trim it\n let response;\n try {\n logger.debug('Downloading GeoIP database hash from: ' + remoteHashUrl);\n response = await fetch(remoteHashUrl, { signal: abortSignal });\n }\n catch (e) {\n // Catching and re-throwing as async exception \n // here is necessary, synch exceptions cannot be caught by the caller\n throw new Error('Fetch error when downloading ' + remoteHashUrl + ', error: ' + e);\n }\n if (!response.ok) {\n throw new Error('HTTP error when downloading ' + remoteHashUrl + ', status: ' + response.status);\n }\n return (await response.text()).trim();\n};\nconst isDbFileValid = (dbFile, remoteHash) => {\n // check if the local db exists and calculate its hash\n try {\n const db = fs.readFileSync(dbFile);\n const localHash = crypto.createHash('sha384').update(db).digest('hex');\n // if the hashes are different, download the latest database\n if (localHash !== remoteHash) {\n return false;\n }\n else {\n return true;\n }\n }\n catch {\n // if the local db does not exist, or some other exception occurres db is not considered valid\n return false;\n }\n};\n// returns a Reader if a new db was downloaded, or if the caller wants to force return a reader\n// also if there was no need to download a new db\nexport const downloadGeoIpDatabase = async (dbFolder, forceReturnReader, abortSignal, mirrorUrl) => {\n // This will throw if the download folder is not readable\n if (!fs.existsSync(dbFolder)) {\n // This will throw if the download folder is not writable\n fs.mkdirSync(dbFolder, { recursive: true });\n }\n if (!dbFolder.endsWith('/')) {\n dbFolder += '/';\n }\n let geoIpMirrorUrl = GEOIP_MIRROR_URL;\n if (mirrorUrl !== undefined) {\n if (!mirrorUrl.endsWith('/')) {\n mirrorUrl += '/';\n }\n geoIpMirrorUrl = mirrorUrl;\n }\n const remoteHashUrl = geoIpMirrorUrl + DB_NAME + HASH_SUFFIX;\n const dbDownloadUrl = geoIpMirrorUrl + DB_NAME + TAR_SUFFFIX;\n const dbFileInDbFolder = dbFolder + DB_NAME + DB_SUFFIX;\n const remoteHash = await downloadRemoteHash(remoteHashUrl, abortSignal);\n const dbValid = isDbFileValid(dbFileInDbFolder, remoteHash);\n if (dbValid === false) {\n await downloadNewDb(dbDownloadUrl, dbFolder, remoteHash, abortSignal);\n // return new reader if db was downloaded\n return new Reader(fs.readFileSync(dbFileInDbFolder));\n }\n else {\n logger.debug('The hash of the local GeoIP database matches the remote hash, no need to download a new database');\n }\n if (forceReturnReader) {\n // return reader also for old db the caller wants it\n return new Reader(fs.readFileSync(dbFileInDbFolder));\n }\n else {\n // return undefined if the db is already up to date\n return undefined;\n }\n};\n//# sourceMappingURL=downloadGeoIpDatabase.js.map","import { Logger, filePathToNodeFormat } from '@streamr/utils';\nimport LongTimeout from 'long-timeout';\nimport { downloadGeoIpDatabase } from './downloadGeoIpDatabase';\nconst logger = new Logger('GeoIpLocator');\n// 30 days in milliseconds\nconst DEFAULT_DB_CHECK_INTERVAL = 30 * 24 * 60 * 60 * 1000;\n// 24 hours in milliseconds\nconst DEFAULT_DB_CHECK_ERROR_INTERVAL = 24 * 60 * 60 * 1000;\nexport class GeoIpLocator {\n abortController;\n geoIpDatabaseFolder;\n dbCheckInterval;\n dbCheckErrorInterval;\n mirrorUrl;\n reader;\n dbCheckTimeout;\n constructor(geoIpDatabaseFolder, dbCheckInterval = DEFAULT_DB_CHECK_INTERVAL, dbCheckErrorInterval = DEFAULT_DB_CHECK_ERROR_INTERVAL, mirrorUrl) {\n this.abortController = new AbortController();\n this.dbCheckInterval = dbCheckInterval;\n this.dbCheckErrorInterval = dbCheckErrorInterval;\n if (!geoIpDatabaseFolder.endsWith('/')) {\n geoIpDatabaseFolder += '/';\n }\n this.geoIpDatabaseFolder = filePathToNodeFormat(geoIpDatabaseFolder);\n this.mirrorUrl = mirrorUrl;\n }\n checkDatabase = async () => {\n if (this.reader === undefined) {\n // if we do not have a reader, create a new one in any case\n this.reader = await downloadGeoIpDatabase(this.geoIpDatabaseFolder, true, this.abortController.signal, this.mirrorUrl);\n }\n else {\n // if we already have a reader, create a new one only if db has changed\n const newReader = await downloadGeoIpDatabase(this.geoIpDatabaseFolder, false, this.abortController.signal, this.mirrorUrl);\n if (newReader !== undefined) {\n this.reader = newReader;\n }\n }\n };\n scheduleCheck = async (timeout) => {\n if (this.abortController.signal.aborted) {\n return;\n }\n this.dbCheckTimeout = LongTimeout.setTimeout(async () => {\n try {\n await this.checkDatabase();\n this.scheduleCheck(this.dbCheckInterval);\n }\n catch (err) {\n logger.warn('GeoIpLocator: GeoIP database check failed', { err });\n this.scheduleCheck(this.dbCheckErrorInterval);\n }\n }, timeout);\n };\n async start() {\n if (this.dbCheckTimeout !== undefined) {\n return;\n }\n await this.checkDatabase();\n this.scheduleCheck(this.dbCheckInterval);\n }\n stop() {\n if (this.dbCheckTimeout !== undefined) {\n LongTimeout.clearTimeout(this.dbCheckTimeout);\n }\n this.abortController.abort();\n }\n lookup(ip) {\n if (this.reader === undefined) {\n logger.warn('GeoIpLocator: lookup called before database is ready (maybe start() was not called?');\n return undefined;\n }\n // If ip is falsy, the library will crash\n // this might happen despite the ts typings because the ip address \n // comes from the ws server socket and is not under our control\n if (!ip) {\n return undefined;\n }\n const result = this.reader.get(ip);\n if (!result?.location?.latitude || !result.location.longitude) {\n return undefined;\n }\n else {\n return {\n latitude: result.location.latitude,\n longitude: result.location.longitude\n };\n }\n }\n}\n//# sourceMappingURL=GeoIpLocator.js.map"],"names":["logger"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@streamr/geoip-location",
|
|
3
|
-
"version": "103.
|
|
3
|
+
"version": "103.2.0-experiment.0",
|
|
4
4
|
"description": "Library for getting location information from IP addresses based on MaxMind GeoLite2 databases",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/streamr-dev/network.git",
|
|
8
8
|
"directory": "packages/geoip-location"
|
|
9
9
|
},
|
|
10
|
-
"main": "dist/
|
|
10
|
+
"main": "./dist/exports.cjs",
|
|
11
|
+
"module": "./dist/exports.js",
|
|
12
|
+
"types": "./dist/exports.d.ts",
|
|
11
13
|
"browser": {
|
|
12
|
-
"dist/
|
|
13
|
-
"dist/src/GeoIpLocator.js": false,
|
|
14
|
-
"dist/src/downloadGeoIpDatabase.js": false
|
|
14
|
+
"./dist/exports.js": false
|
|
15
15
|
},
|
|
16
|
-
"types": "dist/src/exports.d.ts",
|
|
17
16
|
"files": [
|
|
18
|
-
"dist",
|
|
17
|
+
"dist/exports.*",
|
|
19
18
|
"!*.tsbuildinfo",
|
|
20
19
|
"README.md",
|
|
21
20
|
"LICENSE"
|
|
@@ -23,15 +22,18 @@
|
|
|
23
22
|
"license": "Apache-2.0",
|
|
24
23
|
"author": "Streamr Network AG <contact@streamr.network>",
|
|
25
24
|
"scripts": {
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
25
|
+
"prebuild": "npm run reset-self",
|
|
26
|
+
"build": "tsc -b",
|
|
27
|
+
"postbuild": "NODE_OPTIONS='--import tsx' rollup -c rollup.config.mts",
|
|
28
|
+
"check": "tsc -p tsconfig.jest.json",
|
|
29
|
+
"reset-self": "rimraf --glob 'dist/**/*.tsbuildinfo'",
|
|
30
|
+
"clean": "jest --clearCache --config '{}' || true; rm -rf dist *.tsbuildinfo node_modules/.cache || true",
|
|
29
31
|
"eslint": "eslint --cache --cache-location=node_modules/.cache/.eslintcache/ '*/**/*.{js,ts}'",
|
|
30
32
|
"test": "jest test/unit",
|
|
31
33
|
"test-unit": "jest test/unit"
|
|
32
34
|
},
|
|
33
35
|
"dependencies": {
|
|
34
|
-
"@streamr/utils": "103.
|
|
36
|
+
"@streamr/utils": "103.2.0-experiment.0",
|
|
35
37
|
"eventemitter3": "^5.0.0",
|
|
36
38
|
"long-timeout": "^0.1.1",
|
|
37
39
|
"mmdb-lib": "^3.0.1",
|
|
@@ -39,8 +41,13 @@
|
|
|
39
41
|
"uuid": "^11.1.0"
|
|
40
42
|
},
|
|
41
43
|
"devDependencies": {
|
|
44
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
42
45
|
"@types/long-timeout": "^0.1.2",
|
|
43
46
|
"@types/tar": "^6.1.11",
|
|
44
|
-
"express": "^5.
|
|
47
|
+
"express": "^5.2.0",
|
|
48
|
+
"rimraf": "^6.1.2",
|
|
49
|
+
"rollup": "^4.55.1",
|
|
50
|
+
"rollup-plugin-dts": "^6.3.0",
|
|
51
|
+
"tsx": "^4.21.0"
|
|
45
52
|
}
|
|
46
53
|
}
|
package/dist/src/GeoIpLocator.js
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.GeoIpLocator = void 0;
|
|
7
|
-
const utils_1 = require("@streamr/utils");
|
|
8
|
-
const long_timeout_1 = __importDefault(require("long-timeout"));
|
|
9
|
-
const downloadGeoIpDatabase_1 = require("./downloadGeoIpDatabase");
|
|
10
|
-
const logger = new utils_1.Logger(module);
|
|
11
|
-
// 30 days in milliseconds
|
|
12
|
-
const DEFAULT_DB_CHECK_INTERVAL = 30 * 24 * 60 * 60 * 1000;
|
|
13
|
-
// 24 hours in milliseconds
|
|
14
|
-
const DEFAULT_DB_CHECK_ERROR_INTERVAL = 24 * 60 * 60 * 1000;
|
|
15
|
-
class GeoIpLocator {
|
|
16
|
-
abortController;
|
|
17
|
-
geoIpDatabaseFolder;
|
|
18
|
-
dbCheckInterval;
|
|
19
|
-
dbCheckErrorInterval;
|
|
20
|
-
mirrorUrl;
|
|
21
|
-
reader;
|
|
22
|
-
dbCheckTimeout;
|
|
23
|
-
constructor(geoIpDatabaseFolder, dbCheckInterval = DEFAULT_DB_CHECK_INTERVAL, dbCheckErrorInterval = DEFAULT_DB_CHECK_ERROR_INTERVAL, mirrorUrl) {
|
|
24
|
-
this.abortController = new AbortController();
|
|
25
|
-
this.dbCheckInterval = dbCheckInterval;
|
|
26
|
-
this.dbCheckErrorInterval = dbCheckErrorInterval;
|
|
27
|
-
if (!geoIpDatabaseFolder.endsWith('/')) {
|
|
28
|
-
geoIpDatabaseFolder += '/';
|
|
29
|
-
}
|
|
30
|
-
this.geoIpDatabaseFolder = (0, utils_1.filePathToNodeFormat)(geoIpDatabaseFolder);
|
|
31
|
-
this.mirrorUrl = mirrorUrl;
|
|
32
|
-
}
|
|
33
|
-
checkDatabase = async () => {
|
|
34
|
-
if (this.reader === undefined) {
|
|
35
|
-
// if we do not have a reader, create a new one in any case
|
|
36
|
-
this.reader = await (0, downloadGeoIpDatabase_1.downloadGeoIpDatabase)(this.geoIpDatabaseFolder, true, this.abortController.signal, this.mirrorUrl);
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
// if we already have a reader, create a new one only if db has changed
|
|
40
|
-
const newReader = await (0, downloadGeoIpDatabase_1.downloadGeoIpDatabase)(this.geoIpDatabaseFolder, false, this.abortController.signal, this.mirrorUrl);
|
|
41
|
-
if (newReader !== undefined) {
|
|
42
|
-
this.reader = newReader;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
scheduleCheck = async (timeout) => {
|
|
47
|
-
if (this.abortController.signal.aborted) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
this.dbCheckTimeout = long_timeout_1.default.setTimeout(async () => {
|
|
51
|
-
try {
|
|
52
|
-
await this.checkDatabase();
|
|
53
|
-
this.scheduleCheck(this.dbCheckInterval);
|
|
54
|
-
}
|
|
55
|
-
catch (err) {
|
|
56
|
-
logger.warn('GeoIpLocator: GeoIP database check failed', { err });
|
|
57
|
-
this.scheduleCheck(this.dbCheckErrorInterval);
|
|
58
|
-
}
|
|
59
|
-
}, timeout);
|
|
60
|
-
};
|
|
61
|
-
async start() {
|
|
62
|
-
if (this.dbCheckTimeout !== undefined) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
await this.checkDatabase();
|
|
66
|
-
this.scheduleCheck(this.dbCheckInterval);
|
|
67
|
-
}
|
|
68
|
-
stop() {
|
|
69
|
-
if (this.dbCheckTimeout !== undefined) {
|
|
70
|
-
long_timeout_1.default.clearTimeout(this.dbCheckTimeout);
|
|
71
|
-
}
|
|
72
|
-
this.abortController.abort();
|
|
73
|
-
}
|
|
74
|
-
lookup(ip) {
|
|
75
|
-
if (this.reader === undefined) {
|
|
76
|
-
logger.warn('GeoIpLocator: lookup called before database is ready (maybe start() was not called?');
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
// If ip is falsy, the library will crash
|
|
80
|
-
// this might happen despite the ts typings because the ip address
|
|
81
|
-
// comes from the ws server socket and is not under our control
|
|
82
|
-
if (!ip) {
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
85
|
-
const result = this.reader.get(ip);
|
|
86
|
-
if (!result?.location?.latitude || !result.location.longitude) {
|
|
87
|
-
return undefined;
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
return {
|
|
91
|
-
latitude: result.location.latitude,
|
|
92
|
-
longitude: result.location.longitude
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
exports.GeoIpLocator = GeoIpLocator;
|
|
98
|
-
//# sourceMappingURL=GeoIpLocator.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GeoIpLocator.js","sourceRoot":"","sources":["../../src/GeoIpLocator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.downloadGeoIpDatabase = void 0;
|
|
7
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
-
const fs_1 = __importDefault(require("fs"));
|
|
9
|
-
const mmdb_lib_1 = require("mmdb-lib");
|
|
10
|
-
const tarHelper_1 = require("./tarHelper");
|
|
11
|
-
const uuid_1 = require("uuid");
|
|
12
|
-
const utils_1 = require("@streamr/utils");
|
|
13
|
-
const GEOIP_MIRROR_URL = 'https://raw.githubusercontent.com/GitSquared/node-geolite2-redist/master/redist/';
|
|
14
|
-
const DB_NAME = 'GeoLite2-City';
|
|
15
|
-
const TAR_SUFFFIX = '.tar.gz';
|
|
16
|
-
const DB_SUFFIX = '.mmdb';
|
|
17
|
-
const HASH_SUFFIX = '.mmdb.sha384';
|
|
18
|
-
const logger = new utils_1.Logger(module);
|
|
19
|
-
const downloadNewDb = async (url, dbFolder, remoteHash, abortSignal) => {
|
|
20
|
-
// make a unique name for the temporary download folder
|
|
21
|
-
// in case there are multiple downloads happening at the same time
|
|
22
|
-
const uniqueName = (0, uuid_1.v4)();
|
|
23
|
-
const downloadFolder = dbFolder + '.download' + uniqueName;
|
|
24
|
-
const dbFileName = DB_NAME + DB_SUFFIX;
|
|
25
|
-
const dbFileInDownloadFolder = downloadFolder + '/' + dbFileName;
|
|
26
|
-
const dbFileInDbFolder = dbFolder + dbFileName;
|
|
27
|
-
let response;
|
|
28
|
-
try {
|
|
29
|
-
logger.debug('Downloading GeoIP database from: ' + url);
|
|
30
|
-
response = await fetch(url, { keepalive: false, signal: abortSignal });
|
|
31
|
-
}
|
|
32
|
-
catch (e) {
|
|
33
|
-
// Catching and re-throwing as async exception
|
|
34
|
-
// here is necessary, synch exceptions cannot be caught by the caller
|
|
35
|
-
throw new Error('Fetch error when downloading ' + url + ', error: ' + e);
|
|
36
|
-
}
|
|
37
|
-
if (!response.ok) {
|
|
38
|
-
throw new Error('HTTP error when downloading ' + url + ', status: ' + response.status);
|
|
39
|
-
}
|
|
40
|
-
// extract the tarball to a temporary folder
|
|
41
|
-
try {
|
|
42
|
-
fs_1.default.mkdirSync(downloadFolder, { recursive: true });
|
|
43
|
-
}
|
|
44
|
-
catch (e) {
|
|
45
|
-
throw new Error('Error creating temporary folder ' + downloadFolder + ', error: ' + e);
|
|
46
|
-
}
|
|
47
|
-
try {
|
|
48
|
-
await (0, tarHelper_1.extractFileFromTarStream)(dbFileName, response.body, downloadFolder);
|
|
49
|
-
}
|
|
50
|
-
catch (e) {
|
|
51
|
-
try {
|
|
52
|
-
fs_1.default.rmSync(downloadFolder, { recursive: true });
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
// ignore error when removing the temporary folder
|
|
56
|
-
}
|
|
57
|
-
throw e;
|
|
58
|
-
}
|
|
59
|
-
// check the hash of the extracted file
|
|
60
|
-
if (!isDbFileValid(dbFileInDownloadFolder, remoteHash)) {
|
|
61
|
-
try {
|
|
62
|
-
fs_1.default.rmSync(downloadFolder, { recursive: true });
|
|
63
|
-
}
|
|
64
|
-
catch {
|
|
65
|
-
// ignore error when removing the temporary folder
|
|
66
|
-
}
|
|
67
|
-
throw new Error('Downloaded database hash does not match the expected hash');
|
|
68
|
-
}
|
|
69
|
-
try {
|
|
70
|
-
// move the extracted file to the correct location
|
|
71
|
-
fs_1.default.renameSync(dbFileInDownloadFolder, dbFileInDbFolder);
|
|
72
|
-
}
|
|
73
|
-
catch (e) {
|
|
74
|
-
throw new Error('Error moving ' + dbFileInDownloadFolder + ' to ' + dbFileInDbFolder + ', error: ' + e);
|
|
75
|
-
}
|
|
76
|
-
finally {
|
|
77
|
-
try {
|
|
78
|
-
fs_1.default.rmSync(downloadFolder, { recursive: true });
|
|
79
|
-
}
|
|
80
|
-
catch {
|
|
81
|
-
// ignore error when removing the temporary folder
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
// set the db file permissions to rw only for the owner
|
|
85
|
-
try {
|
|
86
|
-
fs_1.default.chmodSync(dbFileInDbFolder, 0o600);
|
|
87
|
-
}
|
|
88
|
-
catch (err) {
|
|
89
|
-
throw new Error('Error setting permissions on ' + dbFileInDbFolder + ', error: ' + err);
|
|
90
|
-
}
|
|
91
|
-
logger.debug('Downloaded GeoIP database to: ' + dbFileInDbFolder);
|
|
92
|
-
};
|
|
93
|
-
const downloadRemoteHash = async (remoteHashUrl, abortSignal) => {
|
|
94
|
-
// download the hash of the latest GeoIP database using fetch as text and trim it
|
|
95
|
-
let response;
|
|
96
|
-
try {
|
|
97
|
-
logger.debug('Downloading GeoIP database hash from: ' + remoteHashUrl);
|
|
98
|
-
response = await fetch(remoteHashUrl, { signal: abortSignal });
|
|
99
|
-
}
|
|
100
|
-
catch (e) {
|
|
101
|
-
// Catching and re-throwing as async exception
|
|
102
|
-
// here is necessary, synch exceptions cannot be caught by the caller
|
|
103
|
-
throw new Error('Fetch error when downloading ' + remoteHashUrl + ', error: ' + e);
|
|
104
|
-
}
|
|
105
|
-
if (!response.ok) {
|
|
106
|
-
throw new Error('HTTP error when downloading ' + remoteHashUrl + ', status: ' + response.status);
|
|
107
|
-
}
|
|
108
|
-
return (await response.text()).trim();
|
|
109
|
-
};
|
|
110
|
-
const isDbFileValid = (dbFile, remoteHash) => {
|
|
111
|
-
// check if the local db exists and calculate its hash
|
|
112
|
-
try {
|
|
113
|
-
const db = fs_1.default.readFileSync(dbFile);
|
|
114
|
-
const localHash = crypto_1.default.createHash('sha384').update(db).digest('hex');
|
|
115
|
-
// if the hashes are different, download the latest database
|
|
116
|
-
if (localHash !== remoteHash) {
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
return true;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
catch {
|
|
124
|
-
// if the local db does not exist, or some other exception occurres db is not considered valid
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
// returns a Reader if a new db was downloaded, or if the caller wants to force return a reader
|
|
129
|
-
// also if there was no need to download a new db
|
|
130
|
-
const downloadGeoIpDatabase = async (dbFolder, forceReturnReader, abortSignal, mirrorUrl) => {
|
|
131
|
-
// This will throw if the download folder is not readable
|
|
132
|
-
if (!fs_1.default.existsSync(dbFolder)) {
|
|
133
|
-
// This will throw if the download folder is not writable
|
|
134
|
-
fs_1.default.mkdirSync(dbFolder, { recursive: true });
|
|
135
|
-
}
|
|
136
|
-
if (!dbFolder.endsWith('/')) {
|
|
137
|
-
dbFolder += '/';
|
|
138
|
-
}
|
|
139
|
-
let geoIpMirrorUrl = GEOIP_MIRROR_URL;
|
|
140
|
-
if (mirrorUrl !== undefined) {
|
|
141
|
-
if (!mirrorUrl.endsWith('/')) {
|
|
142
|
-
mirrorUrl += '/';
|
|
143
|
-
}
|
|
144
|
-
geoIpMirrorUrl = mirrorUrl;
|
|
145
|
-
}
|
|
146
|
-
const remoteHashUrl = geoIpMirrorUrl + DB_NAME + HASH_SUFFIX;
|
|
147
|
-
const dbDownloadUrl = geoIpMirrorUrl + DB_NAME + TAR_SUFFFIX;
|
|
148
|
-
const dbFileInDbFolder = dbFolder + DB_NAME + DB_SUFFIX;
|
|
149
|
-
const remoteHash = await downloadRemoteHash(remoteHashUrl, abortSignal);
|
|
150
|
-
const dbValid = isDbFileValid(dbFileInDbFolder, remoteHash);
|
|
151
|
-
if (dbValid === false) {
|
|
152
|
-
await downloadNewDb(dbDownloadUrl, dbFolder, remoteHash, abortSignal);
|
|
153
|
-
// return new reader if db was downloaded
|
|
154
|
-
return new mmdb_lib_1.Reader(fs_1.default.readFileSync(dbFileInDbFolder));
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
logger.debug('The hash of the local GeoIP database matches the remote hash, no need to download a new database');
|
|
158
|
-
}
|
|
159
|
-
if (forceReturnReader) {
|
|
160
|
-
// return reader also for old db the caller wants it
|
|
161
|
-
return new mmdb_lib_1.Reader(fs_1.default.readFileSync(dbFileInDbFolder));
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
// return undefined if the db is already up to date
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
exports.downloadGeoIpDatabase = downloadGeoIpDatabase;
|
|
169
|
-
//# sourceMappingURL=downloadGeoIpDatabase.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"downloadGeoIpDatabase.js","sourceRoot":"","sources":["../../src/downloadGeoIpDatabase.ts"],"names":[],"mappings":"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"}
|
package/dist/src/exports.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { GeoIpLocator } from './GeoIpLocator';
|
package/dist/src/exports.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GeoIpLocator = void 0;
|
|
4
|
-
var GeoIpLocator_1 = require("./GeoIpLocator");
|
|
5
|
-
Object.defineProperty(exports, "GeoIpLocator", { enumerable: true, get: function () { return GeoIpLocator_1.GeoIpLocator; } });
|
|
6
|
-
//# sourceMappingURL=exports.js.map
|
package/dist/src/exports.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"exports.js","sourceRoot":"","sources":["../../src/exports.ts"],"names":[],"mappings":";;;AAAA,+CAA6C;AAApC,4GAAA,YAAY,OAAA"}
|
package/dist/src/tarHelper.d.ts
DELETED
package/dist/src/tarHelper.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.extractFileFromTarStream = void 0;
|
|
7
|
-
const stream_1 = require("stream");
|
|
8
|
-
const tar_1 = require("tar");
|
|
9
|
-
const path_1 = __importDefault(require("path")); // use NodePath to avoid conflict with other 'path' symbols
|
|
10
|
-
const fs_1 = __importDefault(require("fs"));
|
|
11
|
-
const doExtractFileFromTarStream = (fileName, stream, downloadFolder) => {
|
|
12
|
-
return new Promise((resolve, reject) => {
|
|
13
|
-
try {
|
|
14
|
-
const nodeStream = stream_1.Readable.fromWeb(stream);
|
|
15
|
-
(0, stream_1.pipeline)(nodeStream, (0, tar_1.extract)({
|
|
16
|
-
cwd: downloadFolder,
|
|
17
|
-
filter: (entryPath) => path_1.default.basename(entryPath) === fileName,
|
|
18
|
-
strip: 1
|
|
19
|
-
}), (err) => {
|
|
20
|
-
if (err) {
|
|
21
|
-
reject(new Error('Error extracting tarball to ' + downloadFolder + ', error: ' + err));
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
resolve();
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
catch (e) {
|
|
29
|
-
reject(new Error('Failed to create nodejs Readable from web stream: ' + e));
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
};
|
|
33
|
-
const extractFileFromTarStream = async (fileName, stream, downloadFolder) => {
|
|
34
|
-
await doExtractFileFromTarStream(fileName, stream, downloadFolder);
|
|
35
|
-
if (!fs_1.default.existsSync(path_1.default.join(downloadFolder, fileName))) {
|
|
36
|
-
throw new Error('File not found in tarball: ' + fileName);
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
exports.extractFileFromTarStream = extractFileFromTarStream;
|
|
40
|
-
//# sourceMappingURL=tarHelper.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tarHelper.js","sourceRoot":"","sources":["../../src/tarHelper.ts"],"names":[],"mappings":";;;;;;AAAA,mCAA2C;AAC3C,6BAA6B;AAE7B,gDAA2B,CAAK,2DAA2D;AAC3F,4CAAmB;AAEnB,MAAM,0BAA0B,GAAG,CAAC,QAAgB,EAAE,MAA2B,EAAE,cAAsB,EAAiB,EAAE;IACxH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,IAAI,CAAC;YACD,MAAM,UAAU,GAAG,iBAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;YAC3C,IAAA,iBAAQ,EAAC,UAAU,EACf,IAAA,aAAO,EAAC;gBACJ,GAAG,EAAE,cAAc;gBACnB,MAAM,EAAE,CAAC,SAAiB,EAAW,EAAE,CAAC,cAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,QAAQ;gBACjF,KAAK,EAAE,CAAC;aACX,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE;gBACR,IAAI,GAAG,EAAE,CAAC;oBACN,MAAM,CAAC,IAAI,KAAK,CAAC,8BAA8B,GAAG,cAAc,GAAG,WAAW,GAAG,GAAG,CAAC,CAAC,CAAA;gBAC1F,CAAC;qBAAM,CAAC;oBACJ,OAAO,EAAE,CAAA;gBACb,CAAC;YACL,CAAC,CAAC,CAAA;QACV,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,MAAM,CAAC,IAAI,KAAK,CAAC,oDAAoD,GAAG,CAAC,CAAC,CAAC,CAAA;QAC/E,CAAC;IACL,CAAC,CAAC,CAAA;AACN,CAAC,CAAA;AAEM,MAAM,wBAAwB,GAAG,KAAK,EAAE,QAAgB,EAAE,MAA2B,EAAE,cAAsB,EAAiB,EAAE;IACnI,MAAM,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,CAAC,CAAA;IAClE,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,cAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,QAAQ,CAAC,CAAA;IAC7D,CAAC;AACL,CAAC,CAAA;AALY,QAAA,wBAAwB,4BAKpC"}
|