@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.
@@ -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
- export declare class GeoIpLocator {
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
- export {};
20
+
21
+ export { GeoIpLocator };
@@ -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.1.2-rc.0",
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/src/exports.js",
10
+ "main": "./dist/exports.cjs",
11
+ "module": "./dist/exports.js",
12
+ "types": "./dist/exports.d.ts",
11
13
  "browser": {
12
- "dist/src/exports.js": false,
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
- "build": "tsc -b tsconfig.node.json",
27
- "check": "tsc -p ./tsconfig.jest.json",
28
- "clean": "jest --clearCache || true; rm -rf dist *.tsbuildinfo node_modules/.cache || true",
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.1.2-rc.0",
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.1.0"
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
  }
@@ -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,2 +0,0 @@
1
- import { CityResponse, Reader } from 'mmdb-lib';
2
- export declare const downloadGeoIpDatabase: (dbFolder: string, forceReturnReader: boolean, abortSignal: AbortSignal, mirrorUrl?: string) => Promise<Reader<CityResponse> | undefined>;
@@ -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":";;;;;;AAAA,oDAA2B;AAC3B,4CAAmB;AACnB,uCAA+C;AAC/C,2CAAsD;AACtD,+BAAyB;AACzB,0CAAuC;AAEvC,MAAM,gBAAgB,GAAG,kFAAkF,CAAA;AAC3G,MAAM,OAAO,GAAG,eAAe,CAAA;AAC/B,MAAM,WAAW,GAAG,SAAS,CAAA;AAC7B,MAAM,SAAS,GAAG,OAAO,CAAA;AACzB,MAAM,WAAW,GAAG,cAAc,CAAA;AAElC,MAAM,MAAM,GAAG,IAAI,cAAM,CAAC,MAAM,CAAC,CAAA;AAEjC,MAAM,aAAa,GAAG,KAAK,EACvB,GAAW,EACX,QAAgB,EAChB,UAAkB,EAClB,WAAwB,EACX,EAAE;IACf,uDAAuD;IACvD,kEAAkE;IAElE,MAAM,UAAU,GAAG,IAAA,SAAE,GAAE,CAAA;IACvB,MAAM,cAAc,GAAG,QAAQ,GAAG,WAAW,GAAG,UAAU,CAAA;IAC1D,MAAM,UAAU,GAAG,OAAO,GAAG,SAAS,CAAA;IACtC,MAAM,sBAAsB,GAAG,cAAc,GAAG,GAAG,GAAG,UAAU,CAAA;IAChE,MAAM,gBAAgB,GAAG,QAAQ,GAAG,UAAU,CAAA;IAE9C,IAAI,QAAkB,CAAA;IAEtB,IAAI,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,mCAAmC,GAAG,GAAG,CAAC,CAAA;QACvD,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAA;IAC1E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,+CAA+C;QAC/C,qEAAqE;QACrE,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,GAAG,GAAG,WAAW,GAAG,CAAC,CAAC,CAAA;IAC5E,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,GAAG,GAAG,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC1F,CAAC;IAED,4CAA4C;IAE5C,IAAI,CAAC;QACD,YAAE,CAAC,SAAS,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,kCAAkC,GAAG,cAAc,GAAG,WAAW,GAAG,CAAC,CAAC,CAAA;IAC1F,CAAC;IAED,IAAI,CAAC;QACD,MAAM,IAAA,oCAAwB,EAAC,UAAU,EAAE,QAAQ,CAAC,IAAK,EAAE,cAAc,CAAC,CAAA;IAC9E,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,IAAI,CAAC;YACD,YAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAClD,CAAC;QAAC,MAAM,CAAC;YACL,kDAAkD;QACtD,CAAC;QACD,MAAM,CAAC,CAAA;IACX,CAAC;IAED,uCAAuC;IAEvC,IAAI,CAAC,aAAa,CAAC,sBAAsB,EAAE,UAAU,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC;YACD,YAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAClD,CAAC;QAAC,MAAM,CAAC;YACL,kDAAkD;QACtD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;IAChF,CAAC;IAED,IAAI,CAAC;QACD,kDAAkD;QAClD,YAAE,CAAC,UAAU,CAAC,sBAAsB,EAAE,gBAAgB,CAAC,CAAA;IAC3D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,eAAe,GAAG,sBAAsB,GAAG,MAAM,GAAG,gBAAgB,GAAG,WAAW,GAAG,CAAC,CAAC,CAAA;IAC3G,CAAC;YAAS,CAAC;QACP,IAAI,CAAC;YACD,YAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAClD,CAAC;QAAC,MAAM,CAAC;YACL,kDAAkD;QACtD,CAAC;IACL,CAAC;IAED,uDAAuD;IAEvD,IAAI,CAAC;QACD,YAAE,CAAC,SAAS,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAA;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,gBAAgB,GAAG,WAAW,GAAG,GAAG,CAAC,CAAA;IAC3F,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,gCAAgC,GAAG,gBAAgB,CAAC,CAAA;AAErE,CAAC,CAAA;AAED,MAAM,kBAAkB,GAAG,KAAK,EAAE,aAAqB,EAAE,WAAwB,EAAmB,EAAE;IAClG,iFAAiF;IACjF,IAAI,QAAkB,CAAA;IAEtB,IAAI,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,wCAAwC,GAAG,aAAa,CAAC,CAAA;QACtE,QAAQ,GAAG,MAAM,KAAK,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAA;IAClE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,+CAA+C;QAC/C,qEAAqE;QACrE,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,aAAa,GAAG,WAAW,GAAG,CAAC,CAAC,CAAA;IACtF,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,aAAa,GAAG,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;IACpG,CAAC;IAED,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;AACzC,CAAC,CAAA;AAED,MAAM,aAAa,GAAG,CAAC,MAAc,EAAE,UAAkB,EAAW,EAAE;IAClE,sDAAsD;IAEtD,IAAI,CAAC;QACD,MAAM,EAAE,GAAG,YAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;QAClC,MAAM,SAAS,GAAG,gBAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAEtE,4DAA4D;QAC5D,IAAI,SAAS,KAAK,UAAU,EAAE,CAAC;YAC3B,OAAO,KAAK,CAAA;QAChB,CAAC;aAAM,CAAC;YACJ,OAAO,IAAI,CAAA;QACf,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACL,8FAA8F;QAC9F,OAAO,KAAK,CAAA;IAChB,CAAC;AACL,CAAC,CAAA;AAED,+FAA+F;AAC/F,iDAAiD;AAE1C,MAAM,qBAAqB,GAAG,KAAK,EACtC,QAAgB,EAChB,iBAA0B,EAC1B,WAAwB,EACxB,SAAkB,EACuB,EAAE;IAC3C,yDAAyD;IACzD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,yDAAyD;QACzD,YAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC/C,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,QAAQ,IAAI,GAAG,CAAA;IACnB,CAAC;IACD,IAAI,cAAc,GAAG,gBAAgB,CAAA;IACrC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,SAAS,IAAI,GAAG,CAAA;QACpB,CAAC;QACD,cAAc,GAAG,SAAS,CAAA;IAC9B,CAAC;IACD,MAAM,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,WAAW,CAAA;IAC5D,MAAM,aAAa,GAAG,cAAc,GAAG,OAAO,GAAG,WAAW,CAAA;IAC5D,MAAM,gBAAgB,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAA;IAEvD,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAA;IACvE,MAAM,OAAO,GAAG,aAAa,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAA;IAC3D,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACpB,MAAM,aAAa,CAAC,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAC,CAAA;QACrE,yCAAyC;QACzC,OAAO,IAAI,iBAAM,CAAe,YAAE,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAA;IACtE,CAAC;SAAM,CAAC;QACJ,MAAM,CAAC,KAAK,CAAC,kGAAkG,CAAC,CAAA;IACpH,CAAC;IACD,IAAI,iBAAiB,EAAE,CAAC;QACpB,oDAAoD;QACpD,OAAO,IAAI,iBAAM,CAAe,YAAE,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAA;IACtE,CAAC;SAAM,CAAC;QACJ,mDAAmD;QACnD,OAAO,SAAS,CAAA;IACpB,CAAC;AACL,CAAC,CAAA;AAzCY,QAAA,qBAAqB,yBAyCjC"}
@@ -1 +0,0 @@
1
- export { GeoIpLocator } from './GeoIpLocator';
@@ -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
@@ -1 +0,0 @@
1
- {"version":3,"file":"exports.js","sourceRoot":"","sources":["../../src/exports.ts"],"names":[],"mappings":";;;AAAA,+CAA6C;AAApC,4GAAA,YAAY,OAAA"}
@@ -1,2 +0,0 @@
1
- import { ReadableStream } from 'stream/web';
2
- export declare const extractFileFromTarStream: (fileName: string, stream: ReadableStream<any>, downloadFolder: string) => Promise<void>;
@@ -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"}