@tachybase/plugin-password-policy 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/IPFilterForm.d.ts +1 -0
- package/dist/client/PasswordAttemptForm.d.ts +1 -0
- package/dist/client/PasswordStrengthSettingsForm.d.ts +2 -0
- package/dist/client/SignInFailsTable.d.ts +2 -0
- package/dist/client/UserLocksTable.d.ts +2 -0
- package/dist/client/collections/signInFails.d.ts +2 -0
- package/dist/client/collections/userLocks.d.ts +2 -0
- package/dist/client/hooks/usePasswordStrength.d.ts +11 -0
- package/dist/client/hooks/usePasswordValidator.d.ts +16 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.js +4 -0
- package/dist/client/locale.d.ts +6 -0
- package/dist/constants.d.ts +11 -0
- package/dist/constants.js +44 -0
- package/dist/externalVersion.js +10 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -0
- package/dist/locale/en-US.json +107 -0
- package/dist/locale/zh-CN.json +107 -0
- package/dist/node_modules/geoip-lite/LICENSE +50 -0
- package/dist/node_modules/geoip-lite/data/city.checksum +1 -0
- package/dist/node_modules/geoip-lite/data/country.checksum +1 -0
- package/dist/node_modules/geoip-lite/data/geoip-city-names.dat +0 -0
- package/dist/node_modules/geoip-lite/data/geoip-city.dat +0 -0
- package/dist/node_modules/geoip-lite/data/geoip-city6.dat +0 -0
- package/dist/node_modules/geoip-lite/data/geoip-country.dat +0 -0
- package/dist/node_modules/geoip-lite/data/geoip-country6.dat +0 -0
- package/dist/node_modules/geoip-lite/lib/fsWatcher.js +83 -0
- package/dist/node_modules/geoip-lite/lib/geoip.js +1 -0
- package/dist/node_modules/geoip-lite/lib/utils.js +98 -0
- package/dist/node_modules/geoip-lite/node_modules/.bin/rimraf +17 -0
- package/dist/node_modules/geoip-lite/package.json +1 -0
- package/dist/node_modules/geoip-lite/scripts/updatedb.js +685 -0
- package/dist/node_modules/geoip-lite/test/geo-lookup.js +56 -0
- package/dist/node_modules/geoip-lite/test/memory_usage.js +3 -0
- package/dist/node_modules/geoip-lite/test/tests.js +197 -0
- package/dist/server/actions/IpFilterController.d.ts +7 -0
- package/dist/server/actions/IpFilterController.js +124 -0
- package/dist/server/actions/PasswordAttemptController.d.ts +7 -0
- package/dist/server/actions/PasswordAttemptController.js +123 -0
- package/dist/server/actions/PasswordStrengthController.d.ts +7 -0
- package/dist/server/actions/PasswordStrengthController.js +123 -0
- package/dist/server/actions/SignInFailsController.d.ts +5 -0
- package/dist/server/actions/SignInFailsController.js +156 -0
- package/dist/server/actions/UserLocksController.d.ts +4 -0
- package/dist/server/actions/UserLocksController.js +102 -0
- package/dist/server/collections/ipFilter.d.ts +2 -0
- package/dist/server/collections/ipFilter.js +51 -0
- package/dist/server/collections/passwordAttempt.d.ts +2 -0
- package/dist/server/collections/passwordAttempt.js +55 -0
- package/dist/server/collections/passwordHistory.d.ts +2 -0
- package/dist/server/collections/passwordHistory.js +46 -0
- package/dist/server/collections/passwordStrengthConfig.d.ts +2 -0
- package/dist/server/collections/passwordStrengthConfig.js +59 -0
- package/dist/server/collections/signInFail.d.ts +2 -0
- package/dist/server/collections/signInFail.js +56 -0
- package/dist/server/collections/userLocks.d.ts +2 -0
- package/dist/server/collections/userLocks.js +51 -0
- package/dist/server/collections/users.d.ts +2 -0
- package/dist/server/collections/users.js +42 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +33 -0
- package/dist/server/plugin.d.ts +5 -0
- package/dist/server/plugin.js +129 -0
- package/dist/server/services/IPFilterService.d.ts +49 -0
- package/dist/server/services/IPFilterService.js +270 -0
- package/dist/server/services/PasswordAttemptService.d.ts +75 -0
- package/dist/server/services/PasswordAttemptService.js +595 -0
- package/dist/server/services/PasswordStrengthService.d.ts +28 -0
- package/dist/server/services/PasswordStrengthService.js +313 -0
- package/dist/types/geoip-lite.d.js +0 -0
- package/package.json +25 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
// fetches and converts maxmind lite databases
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
var user_agent = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.36 Safari/537.36';
|
|
6
|
+
|
|
7
|
+
var fs = require('fs');
|
|
8
|
+
var http = require('http');
|
|
9
|
+
var https = require('https');
|
|
10
|
+
var path = require('path');
|
|
11
|
+
var url = require('url');
|
|
12
|
+
var zlib = require('zlib');
|
|
13
|
+
var readline = require('readline');
|
|
14
|
+
|
|
15
|
+
fs.existsSync = fs.existsSync || path.existsSync;
|
|
16
|
+
|
|
17
|
+
var async = require('async');
|
|
18
|
+
var chalk = require('chalk');
|
|
19
|
+
var iconv = require('iconv-lite');
|
|
20
|
+
var lazy = require('lazy');
|
|
21
|
+
var rimraf = require('rimraf').sync;
|
|
22
|
+
var yauzl = require('yauzl');
|
|
23
|
+
var utils = require('../lib/utils');
|
|
24
|
+
var Address6 = require('ip-address').Address6;
|
|
25
|
+
var Address4 = require('ip-address').Address4;
|
|
26
|
+
|
|
27
|
+
var args = process.argv.slice(2);
|
|
28
|
+
var license_key = args.find(function(arg) {
|
|
29
|
+
return arg.match(/^license_key=[a-zA-Z0-9]+/) !== null;
|
|
30
|
+
});
|
|
31
|
+
if (typeof license_key === 'undefined' && typeof process.env.LICENSE_KEY !== 'undefined') {
|
|
32
|
+
license_key = 'license_key='+process.env.LICENSE_KEY;
|
|
33
|
+
}
|
|
34
|
+
var geodatadir = args.find(function(arg) {
|
|
35
|
+
return arg.match(/^geodatadir=[\w./]+/) !== null;
|
|
36
|
+
});
|
|
37
|
+
if (typeof geodatadir === 'undefined' && typeof process.env.GEODATADIR !== 'undefined') {
|
|
38
|
+
geodatadir = 'geodatadir='+process.env.GEODATADIR;
|
|
39
|
+
}
|
|
40
|
+
var dataPath = path.resolve(__dirname, '..', 'data');
|
|
41
|
+
if (typeof geodatadir !== 'undefined') {
|
|
42
|
+
dataPath = path.resolve(process.cwd(), geodatadir.split('=')[1]);
|
|
43
|
+
if (!fs.existsSync(dataPath)) {
|
|
44
|
+
console.log(chalk.red('ERROR') + ': Directory does\'t exist: ' + dataPath);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
var tmpPath = process.env.GEOTMPDIR ? process.env.GEOTMPDIR : path.resolve(__dirname, '..', 'tmp');
|
|
49
|
+
var countryLookup = {};
|
|
50
|
+
var cityLookup = {NaN: -1};
|
|
51
|
+
var databases = [
|
|
52
|
+
{
|
|
53
|
+
type: 'country',
|
|
54
|
+
url: 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&suffix=zip&'+license_key,
|
|
55
|
+
checksum: 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&suffix=zip.sha256&'+license_key,
|
|
56
|
+
fileName: 'GeoLite2-Country-CSV.zip',
|
|
57
|
+
src: [
|
|
58
|
+
'GeoLite2-Country-Locations-en.csv',
|
|
59
|
+
'GeoLite2-Country-Blocks-IPv4.csv',
|
|
60
|
+
'GeoLite2-Country-Blocks-IPv6.csv'
|
|
61
|
+
],
|
|
62
|
+
dest: [
|
|
63
|
+
'',
|
|
64
|
+
'geoip-country.dat',
|
|
65
|
+
'geoip-country6.dat'
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: 'city',
|
|
70
|
+
url: 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City-CSV&suffix=zip&'+license_key,
|
|
71
|
+
checksum: 'https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City-CSV&suffix=zip.sha256&'+license_key,
|
|
72
|
+
fileName: 'GeoLite2-City-CSV.zip',
|
|
73
|
+
src: [
|
|
74
|
+
'GeoLite2-City-Locations-en.csv',
|
|
75
|
+
'GeoLite2-City-Blocks-IPv4.csv',
|
|
76
|
+
'GeoLite2-City-Blocks-IPv6.csv'
|
|
77
|
+
],
|
|
78
|
+
dest: [
|
|
79
|
+
'geoip-city-names.dat',
|
|
80
|
+
'geoip-city.dat',
|
|
81
|
+
'geoip-city6.dat'
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
function mkdir(name) {
|
|
87
|
+
var dir = path.dirname(name);
|
|
88
|
+
if (!fs.existsSync(dir)) {
|
|
89
|
+
fs.mkdirSync(dir);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Ref: http://stackoverflow.com/questions/8493195/how-can-i-parse-a-csv-string-with-javascript
|
|
94
|
+
// Return array of string values, or NULL if CSV string not well formed.
|
|
95
|
+
// Return array of string values, or NULL if CSV string not well formed.
|
|
96
|
+
|
|
97
|
+
function try_fixing_line(line) {
|
|
98
|
+
var pos1 = 0;
|
|
99
|
+
var pos2 = -1;
|
|
100
|
+
// escape quotes
|
|
101
|
+
line = line.replace(/""/,'\\"').replace(/'/g,"\\'");
|
|
102
|
+
|
|
103
|
+
while(pos1 < line.length && pos2 < line.length) {
|
|
104
|
+
pos1 = pos2;
|
|
105
|
+
pos2 = line.indexOf(',', pos1 + 1);
|
|
106
|
+
if(pos2 < 0) pos2 = line.length;
|
|
107
|
+
if(line.indexOf("'", (pos1 || 0)) > -1 && line.indexOf("'", pos1) < pos2 && line[pos1 + 1] != '"' && line[pos2 - 1] != '"') {
|
|
108
|
+
line = line.substr(0, pos1 + 1) + '"' + line.substr(pos1 + 1, pos2 - pos1 - 1) + '"' + line.substr(pos2, line.length - pos2);
|
|
109
|
+
pos2 = line.indexOf(',', pos2 + 1);
|
|
110
|
+
if(pos2 < 0) pos2 = line.length;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return line;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function CSVtoArray(text) {
|
|
117
|
+
var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/;
|
|
118
|
+
var re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;
|
|
119
|
+
// Return NULL if input string is not well formed CSV string.
|
|
120
|
+
if (!re_valid.test(text)){
|
|
121
|
+
text = try_fixing_line(text);
|
|
122
|
+
if(!re_valid.test(text))
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
var a = []; // Initialize array to receive values.
|
|
126
|
+
text.replace(re_value, // "Walk" the string using replace with callback.
|
|
127
|
+
function(m0, m1, m2, m3) {
|
|
128
|
+
// Remove backslash from \' in single quoted values.
|
|
129
|
+
if (m1 !== undefined) a.push(m1.replace(/\\'/g, "'"));
|
|
130
|
+
// Remove backslash from \" in double quoted values.
|
|
131
|
+
else if (m2 !== undefined) a.push(m2.replace(/\\"/g, '"').replace(/\\'/g, "'"));
|
|
132
|
+
else if (m3 !== undefined) a.push(m3);
|
|
133
|
+
return ''; // Return empty string.
|
|
134
|
+
});
|
|
135
|
+
// Handle special case of empty last value.
|
|
136
|
+
if (/,\s*$/.test(text)) a.push('');
|
|
137
|
+
return a;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function getHTTPOptions(downloadUrl) {
|
|
141
|
+
var options = url.parse(downloadUrl);
|
|
142
|
+
options.headers = {
|
|
143
|
+
'User-Agent': user_agent
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
if (process.env.http_proxy || process.env.https_proxy) {
|
|
147
|
+
try {
|
|
148
|
+
var HttpsProxyAgent = require('https-proxy-agent');
|
|
149
|
+
options.agent = new HttpsProxyAgent(process.env.http_proxy || process.env.https_proxy);
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
console.error("Install https-proxy-agent to use an HTTP/HTTPS proxy");
|
|
153
|
+
process.exit(-1);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return options;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function check(database, cb) {
|
|
161
|
+
if (args.indexOf("force") !== -1) {
|
|
162
|
+
//we are forcing database upgrade,
|
|
163
|
+
//so not even using checksums
|
|
164
|
+
return cb(null, database);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
var checksumUrl = database.checksum;
|
|
168
|
+
|
|
169
|
+
if (typeof checksumUrl === "undefined") {
|
|
170
|
+
//no checksum url to check, skipping
|
|
171
|
+
return cb(null, database);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
//read existing checksum file
|
|
175
|
+
fs.readFile(path.join(dataPath, database.type+".checksum"), {encoding: 'utf8'}, function(err, data) {
|
|
176
|
+
if (!err && data && data.length) {
|
|
177
|
+
database.checkValue = data;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
console.log('Checking ', database.fileName);
|
|
181
|
+
|
|
182
|
+
function onResponse(response) {
|
|
183
|
+
var status = response.statusCode;
|
|
184
|
+
|
|
185
|
+
if(status === 301 || status === 302 || status === 303 || status === 307 || status === 308) {
|
|
186
|
+
return https.get(getHTTPOptions(response.headers.location), onResponse);
|
|
187
|
+
} else if (status !== 200) {
|
|
188
|
+
console.log(chalk.red('ERROR') + ': HTTP Request Failed [%d %s]', status, http.STATUS_CODES[status]);
|
|
189
|
+
client.abort();
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
var str = "";
|
|
194
|
+
response.on("data", function (chunk) {
|
|
195
|
+
str += chunk;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
response.on("end", function () {
|
|
199
|
+
if (str && str.length) {
|
|
200
|
+
if (str == database.checkValue) {
|
|
201
|
+
console.log(chalk.green('Database "' + database.type + '" is up to date'));
|
|
202
|
+
database.skip = true;
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
console.log(chalk.green('Database ' + database.type + ' has new data'));
|
|
206
|
+
database.checkValue = str;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
console.log(chalk.red('ERROR') + ': Could not retrieve checksum for', database.type, chalk.red('Aborting'));
|
|
211
|
+
console.log('Run with "force" to update without checksum');
|
|
212
|
+
client.abort();
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
cb(null, database);
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
var client = https.get(getHTTPOptions(checksumUrl), onResponse);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function fetch(database, cb) {
|
|
224
|
+
|
|
225
|
+
if (database.skip) {
|
|
226
|
+
return cb(null, null, null, database);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
var downloadUrl = database.url;
|
|
230
|
+
var fileName = database.fileName;
|
|
231
|
+
var gzip = path.extname(fileName) === '.gz';
|
|
232
|
+
|
|
233
|
+
if (gzip) {
|
|
234
|
+
fileName = fileName.replace('.gz', '');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
var tmpFile = path.join(tmpPath, fileName);
|
|
238
|
+
|
|
239
|
+
if (fs.existsSync(tmpFile)) {
|
|
240
|
+
return cb(null, tmpFile, fileName, database);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
console.log('Fetching ', fileName);
|
|
244
|
+
|
|
245
|
+
function onResponse(response) {
|
|
246
|
+
var status = response.statusCode;
|
|
247
|
+
|
|
248
|
+
if(status === 301 || status === 302 || status === 303 || status === 307 || status === 308) {
|
|
249
|
+
return https.get(getHTTPOptions(response.headers.location), onResponse);
|
|
250
|
+
} else if (status !== 200) {
|
|
251
|
+
console.log(chalk.red('ERROR') + ': HTTP Request Failed [%d %s]', status, http.STATUS_CODES[status]);
|
|
252
|
+
client.abort();
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
var tmpFilePipe;
|
|
257
|
+
var tmpFileStream = fs.createWriteStream(tmpFile);
|
|
258
|
+
|
|
259
|
+
if (gzip) {
|
|
260
|
+
tmpFilePipe = response.pipe(zlib.createGunzip()).pipe(tmpFileStream);
|
|
261
|
+
} else {
|
|
262
|
+
tmpFilePipe = response.pipe(tmpFileStream);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
tmpFilePipe.on('close', function() {
|
|
266
|
+
console.log(chalk.green(' DONE'));
|
|
267
|
+
cb(null, tmpFile, fileName, database);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
mkdir(tmpFile);
|
|
272
|
+
|
|
273
|
+
var client = https.get(getHTTPOptions(downloadUrl), onResponse);
|
|
274
|
+
|
|
275
|
+
process.stdout.write('Retrieving ' + fileName + ' ...');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function extract(tmpFile, tmpFileName, database, cb) {
|
|
279
|
+
if (database.skip) {
|
|
280
|
+
return cb(null, database);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (path.extname(tmpFileName) !== '.zip') {
|
|
284
|
+
cb(null, database);
|
|
285
|
+
} else {
|
|
286
|
+
process.stdout.write('Extracting ' + tmpFileName + ' ...');
|
|
287
|
+
yauzl.open(tmpFile, {autoClose: true, lazyEntries: true}, function(err, zipfile) {
|
|
288
|
+
if (err) {
|
|
289
|
+
throw err;
|
|
290
|
+
}
|
|
291
|
+
zipfile.readEntry();
|
|
292
|
+
zipfile.on("entry", function(entry) {
|
|
293
|
+
if (/\/$/.test(entry.fileName)) {
|
|
294
|
+
// Directory file names end with '/'.
|
|
295
|
+
// Note that entries for directories themselves are optional.
|
|
296
|
+
// An entry's fileName implicitly requires its parent directories to exist.
|
|
297
|
+
zipfile.readEntry();
|
|
298
|
+
} else {
|
|
299
|
+
// file entry
|
|
300
|
+
zipfile.openReadStream(entry, function(err, readStream) {
|
|
301
|
+
if (err) {
|
|
302
|
+
throw err;
|
|
303
|
+
}
|
|
304
|
+
readStream.on("end", function() {
|
|
305
|
+
zipfile.readEntry();
|
|
306
|
+
});
|
|
307
|
+
var filePath = entry.fileName.split("/");
|
|
308
|
+
// filePath will always have length >= 1, as split() always returns an array of at least one string
|
|
309
|
+
var fileName = filePath[filePath.length - 1];
|
|
310
|
+
readStream.pipe(fs.createWriteStream(path.join(tmpPath, fileName)));
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
zipfile.once("end", function() {
|
|
315
|
+
console.log(chalk.green(' DONE'));
|
|
316
|
+
cb(null, database);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function processLookupCountry(src, cb){
|
|
323
|
+
function processLine(line) {
|
|
324
|
+
var fields = CSVtoArray(line);
|
|
325
|
+
if (!fields || fields.length < 6) {
|
|
326
|
+
console.log("weird line: %s::", line);
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
countryLookup[fields[0]] = fields[4];
|
|
330
|
+
}
|
|
331
|
+
var tmpDataFile = path.join(tmpPath, src);
|
|
332
|
+
|
|
333
|
+
process.stdout.write('Processing Lookup Data (may take a moment) ...');
|
|
334
|
+
|
|
335
|
+
lazy(fs.createReadStream(tmpDataFile))
|
|
336
|
+
.lines
|
|
337
|
+
.map(function(byteArray) {
|
|
338
|
+
return iconv.decode(byteArray, 'latin1');
|
|
339
|
+
})
|
|
340
|
+
.skip(1)
|
|
341
|
+
.map(processLine)
|
|
342
|
+
.on('pipe', function() {
|
|
343
|
+
console.log(chalk.green(' DONE'));
|
|
344
|
+
cb();
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async function processCountryData(src, dest) {
|
|
349
|
+
var lines=0;
|
|
350
|
+
async function processLine(line) {
|
|
351
|
+
var fields = CSVtoArray(line);
|
|
352
|
+
|
|
353
|
+
if (!fields || fields.length < 6) {
|
|
354
|
+
console.log("weird line: %s::", line);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
lines++;
|
|
358
|
+
|
|
359
|
+
var sip;
|
|
360
|
+
var eip;
|
|
361
|
+
var rngip;
|
|
362
|
+
var cc = countryLookup[fields[1]];
|
|
363
|
+
var b;
|
|
364
|
+
var bsz;
|
|
365
|
+
var i;
|
|
366
|
+
if(cc){
|
|
367
|
+
if (fields[0].match(/:/)) {
|
|
368
|
+
// IPv6
|
|
369
|
+
bsz = 34;
|
|
370
|
+
rngip = new Address6(fields[0]);
|
|
371
|
+
sip = utils.aton6(rngip.startAddress().correctForm());
|
|
372
|
+
eip = utils.aton6(rngip.endAddress().correctForm());
|
|
373
|
+
|
|
374
|
+
b = Buffer.alloc(bsz);
|
|
375
|
+
for (i = 0; i < sip.length; i++) {
|
|
376
|
+
b.writeUInt32BE(sip[i], i * 4);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
for (i = 0; i < eip.length; i++) {
|
|
380
|
+
b.writeUInt32BE(eip[i], 16 + (i * 4));
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
// IPv4
|
|
384
|
+
bsz = 10;
|
|
385
|
+
|
|
386
|
+
rngip = new Address4(fields[0]);
|
|
387
|
+
sip = parseInt(rngip.startAddress().bigInteger(),10);
|
|
388
|
+
eip = parseInt(rngip.endAddress().bigInteger(),10);
|
|
389
|
+
|
|
390
|
+
b = Buffer.alloc(bsz);
|
|
391
|
+
b.fill(0);
|
|
392
|
+
b.writeUInt32BE(sip, 0);
|
|
393
|
+
b.writeUInt32BE(eip, 4);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
b.write(cc, bsz - 2);
|
|
397
|
+
if(Date.now() - tstart > 5000) {
|
|
398
|
+
tstart = Date.now();
|
|
399
|
+
process.stdout.write('\nStill working (' + lines + ') ...');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
if(datFile._writableState.needDrain) {
|
|
403
|
+
return new Promise((resolve) => {
|
|
404
|
+
datFile.write(b, resolve);
|
|
405
|
+
});
|
|
406
|
+
} else {
|
|
407
|
+
return datFile.write(b);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
var dataFile = path.join(dataPath, dest);
|
|
413
|
+
var tmpDataFile = path.join(tmpPath, src);
|
|
414
|
+
|
|
415
|
+
rimraf(dataFile);
|
|
416
|
+
mkdir(dataFile);
|
|
417
|
+
|
|
418
|
+
process.stdout.write('Processing Data (may take a moment) ...');
|
|
419
|
+
var tstart = Date.now();
|
|
420
|
+
var datFile = fs.createWriteStream(dataFile);
|
|
421
|
+
|
|
422
|
+
var rl = readline.createInterface({
|
|
423
|
+
input: fs.createReadStream(tmpDataFile),
|
|
424
|
+
crlfDelay: Infinity
|
|
425
|
+
});
|
|
426
|
+
var i = 0;
|
|
427
|
+
for await (var line of rl) {
|
|
428
|
+
i++;
|
|
429
|
+
if(i == 1) continue;
|
|
430
|
+
await processLine(line);
|
|
431
|
+
}
|
|
432
|
+
datFile.close();
|
|
433
|
+
console.log(chalk.green(' DONE'));
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async function processCityData(src, dest) {
|
|
437
|
+
var lines = 0;
|
|
438
|
+
async function processLine(line) {
|
|
439
|
+
if (line.match(/^Copyright/) || !line.match(/\d/)) {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
var fields = CSVtoArray(line);
|
|
444
|
+
if (!fields) {
|
|
445
|
+
console.log("weird line: %s::", line);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
var sip;
|
|
449
|
+
var eip;
|
|
450
|
+
var rngip;
|
|
451
|
+
var locId;
|
|
452
|
+
var b;
|
|
453
|
+
var bsz;
|
|
454
|
+
var lat;
|
|
455
|
+
var lon;
|
|
456
|
+
var area;
|
|
457
|
+
|
|
458
|
+
var i;
|
|
459
|
+
|
|
460
|
+
lines++;
|
|
461
|
+
|
|
462
|
+
if (fields[0].match(/:/)) {
|
|
463
|
+
// IPv6
|
|
464
|
+
var offset = 0;
|
|
465
|
+
bsz = 48;
|
|
466
|
+
rngip = new Address6(fields[0]);
|
|
467
|
+
sip = utils.aton6(rngip.startAddress().correctForm());
|
|
468
|
+
eip = utils.aton6(rngip.endAddress().correctForm());
|
|
469
|
+
locId = parseInt(fields[1], 10);
|
|
470
|
+
locId = cityLookup[locId];
|
|
471
|
+
|
|
472
|
+
b = Buffer.alloc(bsz);
|
|
473
|
+
b.fill(0);
|
|
474
|
+
|
|
475
|
+
for (i = 0; i < sip.length; i++) {
|
|
476
|
+
b.writeUInt32BE(sip[i], offset);
|
|
477
|
+
offset += 4;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
for (i = 0; i < eip.length; i++) {
|
|
481
|
+
b.writeUInt32BE(eip[i], offset);
|
|
482
|
+
offset += 4;
|
|
483
|
+
}
|
|
484
|
+
b.writeUInt32BE(locId>>>0, 32);
|
|
485
|
+
|
|
486
|
+
lat = Math.round(parseFloat(fields[7]) * 10000);
|
|
487
|
+
lon = Math.round(parseFloat(fields[8]) * 10000);
|
|
488
|
+
area = parseInt(fields[9], 10);
|
|
489
|
+
b.writeInt32BE(lat,36);
|
|
490
|
+
b.writeInt32BE(lon,40);
|
|
491
|
+
b.writeInt32BE(area,44);
|
|
492
|
+
} else {
|
|
493
|
+
// IPv4
|
|
494
|
+
bsz = 24;
|
|
495
|
+
|
|
496
|
+
rngip = new Address4(fields[0]);
|
|
497
|
+
sip = parseInt(rngip.startAddress().bigInteger(),10);
|
|
498
|
+
eip = parseInt(rngip.endAddress().bigInteger(),10);
|
|
499
|
+
locId = parseInt(fields[1], 10);
|
|
500
|
+
locId = cityLookup[locId];
|
|
501
|
+
b = Buffer.alloc(bsz);
|
|
502
|
+
b.fill(0);
|
|
503
|
+
b.writeUInt32BE(sip>>>0, 0);
|
|
504
|
+
b.writeUInt32BE(eip>>>0, 4);
|
|
505
|
+
b.writeUInt32BE(locId>>>0, 8);
|
|
506
|
+
|
|
507
|
+
lat = Math.round(parseFloat(fields[7]) * 10000);
|
|
508
|
+
lon = Math.round(parseFloat(fields[8]) * 10000);
|
|
509
|
+
area = parseInt(fields[9], 10);
|
|
510
|
+
b.writeInt32BE(lat,12);
|
|
511
|
+
b.writeInt32BE(lon,16);
|
|
512
|
+
b.writeInt32BE(area,20);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if(Date.now() - tstart > 5000) {
|
|
516
|
+
tstart = Date.now();
|
|
517
|
+
process.stdout.write('\nStill working (' + lines + ') ...');
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if(datFile._writableState.needDrain) {
|
|
521
|
+
return new Promise((resolve) => {
|
|
522
|
+
datFile.write(b, resolve);
|
|
523
|
+
});
|
|
524
|
+
} else {
|
|
525
|
+
return datFile.write(b);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
var dataFile = path.join(dataPath, dest);
|
|
530
|
+
var tmpDataFile = path.join(tmpPath, src);
|
|
531
|
+
|
|
532
|
+
rimraf(dataFile);
|
|
533
|
+
|
|
534
|
+
process.stdout.write('Processing Data (may take a moment) ...');
|
|
535
|
+
var tstart = Date.now();
|
|
536
|
+
var datFile = fs.createWriteStream(dataFile);
|
|
537
|
+
|
|
538
|
+
var rl = readline.createInterface({
|
|
539
|
+
input: fs.createReadStream(tmpDataFile),
|
|
540
|
+
crlfDelay: Infinity
|
|
541
|
+
});
|
|
542
|
+
var i = 0;
|
|
543
|
+
for await (var line of rl) {
|
|
544
|
+
i++;
|
|
545
|
+
if(i == 1) continue;
|
|
546
|
+
await processLine(line);
|
|
547
|
+
}
|
|
548
|
+
datFile.close();
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function processCityDataNames(src, dest, cb) {
|
|
552
|
+
var locId = null;
|
|
553
|
+
var linesCount = 0;
|
|
554
|
+
function processLine(line) {
|
|
555
|
+
if (line.match(/^Copyright/) || !line.match(/\d/)) {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
var b;
|
|
560
|
+
var sz = 88;
|
|
561
|
+
var fields = CSVtoArray(line);
|
|
562
|
+
if (!fields) {
|
|
563
|
+
//lots of cities contain ` or ' in the name and can't be parsed correctly with current method
|
|
564
|
+
console.log("weird line: %s::", line);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
locId = parseInt(fields[0]);
|
|
569
|
+
|
|
570
|
+
cityLookup[locId] = linesCount;
|
|
571
|
+
var cc = fields[4];
|
|
572
|
+
var rg = fields[6];
|
|
573
|
+
var city = fields[10];
|
|
574
|
+
var metro = parseInt(fields[11]);
|
|
575
|
+
//other possible fields to include
|
|
576
|
+
var tz = fields[12];
|
|
577
|
+
var eu = fields[13];
|
|
578
|
+
|
|
579
|
+
b = Buffer.alloc(sz);
|
|
580
|
+
b.fill(0);
|
|
581
|
+
b.write(cc, 0);//country code
|
|
582
|
+
b.write(rg, 2);//region
|
|
583
|
+
|
|
584
|
+
if(metro) {
|
|
585
|
+
b.writeInt32BE(metro, 5);
|
|
586
|
+
}
|
|
587
|
+
b.write(eu,9);//is in eu
|
|
588
|
+
b.write(tz,10);//timezone
|
|
589
|
+
b.write(city, 42);//cityname
|
|
590
|
+
|
|
591
|
+
fs.writeSync(datFile, b, 0, b.length, null);
|
|
592
|
+
linesCount++;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
var dataFile = path.join(dataPath, dest);
|
|
596
|
+
var tmpDataFile = path.join(tmpPath, src);
|
|
597
|
+
|
|
598
|
+
rimraf(dataFile);
|
|
599
|
+
|
|
600
|
+
var datFile = fs.openSync(dataFile, "w");
|
|
601
|
+
|
|
602
|
+
lazy(fs.createReadStream(tmpDataFile))
|
|
603
|
+
.lines
|
|
604
|
+
.map(function(byteArray) {
|
|
605
|
+
return iconv.decode(byteArray, 'utf-8');
|
|
606
|
+
})
|
|
607
|
+
.skip(1)
|
|
608
|
+
.map(processLine)
|
|
609
|
+
.on('pipe', cb);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
function processData(database, cb) {
|
|
613
|
+
if (database.skip) {
|
|
614
|
+
return cb(null, database);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
var type = database.type;
|
|
618
|
+
var src = database.src;
|
|
619
|
+
var dest = database.dest;
|
|
620
|
+
|
|
621
|
+
if (type === 'country') {
|
|
622
|
+
if(Array.isArray(src)){
|
|
623
|
+
processLookupCountry(src[0], function() {
|
|
624
|
+
processCountryData(src[1], dest[1]).then(() => {
|
|
625
|
+
return processCountryData(src[2], dest[2]);
|
|
626
|
+
}).then(() => {
|
|
627
|
+
cb(null, database);
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
else{
|
|
632
|
+
processCountryData(src, dest, function() {
|
|
633
|
+
cb(null, database);
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
} else if (type === 'city') {
|
|
637
|
+
processCityDataNames(src[0], dest[0], function() {
|
|
638
|
+
processCityData(src[1], dest[1]).then(() => {
|
|
639
|
+
console.log("city data processed");
|
|
640
|
+
return processCityData(src[2], dest[2]);
|
|
641
|
+
}).then(() => {
|
|
642
|
+
console.log(chalk.green(' DONE'));
|
|
643
|
+
cb(null, database);
|
|
644
|
+
});
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function updateChecksum(database, cb) {
|
|
650
|
+
if (database.skip || !database.checkValue) {
|
|
651
|
+
//don't need to update checksums cause it was not fetched or did not change
|
|
652
|
+
return cb();
|
|
653
|
+
}
|
|
654
|
+
fs.writeFile(path.join(dataPath, database.type+".checksum"), database.checkValue, 'utf8', function(err){
|
|
655
|
+
if (err) console.log(chalk.red('Failed to Update checksums.'), "Database:", database.type);
|
|
656
|
+
cb();
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
if (!license_key) {
|
|
661
|
+
console.log(chalk.red('ERROR') + ': Missing license_key');
|
|
662
|
+
process.exit(1);
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
rimraf(tmpPath);
|
|
666
|
+
mkdir(tmpPath);
|
|
667
|
+
|
|
668
|
+
async.eachSeries(databases, function(database, nextDatabase) {
|
|
669
|
+
|
|
670
|
+
async.seq(check, fetch, extract, processData, updateChecksum)(database, nextDatabase);
|
|
671
|
+
|
|
672
|
+
}, function(err) {
|
|
673
|
+
if (err) {
|
|
674
|
+
console.log(chalk.red('Failed to Update Databases from MaxMind.'), err);
|
|
675
|
+
process.exit(1);
|
|
676
|
+
} else {
|
|
677
|
+
console.log(chalk.green('Successfully Updated Databases from MaxMind.'));
|
|
678
|
+
if (args.indexOf("debug") !== -1) {
|
|
679
|
+
console.log(chalk.yellow.bold('Notice: temporary files are not deleted for debug purposes.'));
|
|
680
|
+
} else {
|
|
681
|
+
rimraf(tmpPath);
|
|
682
|
+
}
|
|
683
|
+
process.exit(0);
|
|
684
|
+
}
|
|
685
|
+
});
|