whistle 2.10.1 → 2.10.3
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/assets/js/log.js +44 -27
- package/assets/menu.html +2 -0
- package/assets/modal.html +2 -0
- package/assets/tab.html +3 -3
- package/bin/use.js +236 -101
- package/bin/util.js +10 -7
- package/bin/whistle.js +5 -5
- package/biz/webui/cgi-bin/download.js +1 -1
- package/biz/webui/cgi-bin/get-data.js +0 -5
- package/biz/webui/cgi-bin/init.js +0 -2
- package/biz/webui/cgi-bin/rules/clear-dns-cache.js +7 -0
- package/biz/webui/htdocs/index.html +2 -2
- package/biz/webui/htdocs/js/index.js +53 -50
- package/biz/webui/lib/index.js +49 -4
- package/lib/config.js +6 -4
- package/lib/handlers/file-proxy.js +1 -1
- package/lib/https/ca.js +39 -9
- package/lib/https/index.js +109 -114
- package/lib/index.js +1 -5
- package/lib/inspectors/data.js +119 -13
- package/lib/inspectors/log.js +4 -0
- package/lib/inspectors/req.js +5 -3
- package/lib/inspectors/weinre.js +7 -2
- package/lib/plugins/get-plugins-sync.js +15 -11
- package/lib/plugins/get-plugins.js +11 -12
- package/lib/plugins/load-plugin.js +1 -1
- package/lib/plugins/module-paths.js +4 -0
- package/lib/plugins/util.js +8 -0
- package/lib/rules/dns.js +4 -0
- package/lib/rules/index.js +0 -1
- package/lib/rules/protocols.js +3 -9
- package/lib/rules/rules.js +21 -22
- package/lib/service/composer.js +10 -5
- package/lib/{util/log-server.js → service/console-log.js} +37 -34
- package/lib/service/index.js +2 -4
- package/lib/service/service.js +64 -15
- package/lib/service/util.js +3 -42
- package/lib/socket-mgr.js +2 -16
- package/lib/tunnel.js +2 -4
- package/lib/upgrade.js +1 -1
- package/lib/util/common.js +115 -17
- package/lib/util/index.js +48 -40
- package/package.json +2 -2
- package/biz/webui/cgi-bin/import-remote.js +0 -37
- package/biz/webui/cgi-bin/log/set.js +0 -7
- package/lib/util/parse-query.js +0 -35
package/lib/service/composer.js
CHANGED
|
@@ -38,7 +38,12 @@ function saveComposerHistory() {
|
|
|
38
38
|
} catch (e) {}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function
|
|
41
|
+
function getUrl(url, isConn) {
|
|
42
|
+
url = isConn ? url.replace(/[?#].*$/, '') : url;
|
|
43
|
+
return url.length > MAX_URL_LEN ? url.substring(0, MAX_URL_LEN) : url;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function handleComposerHistory(data, isConn) {
|
|
42
47
|
var url = data.url;
|
|
43
48
|
var method = data.method;
|
|
44
49
|
var headers = data.headers;
|
|
@@ -50,7 +55,7 @@ function handleComposerHistory(data) {
|
|
|
50
55
|
var result = {
|
|
51
56
|
date: Date.now(),
|
|
52
57
|
useH2: data.useH2,
|
|
53
|
-
url: url
|
|
58
|
+
url: getUrl(url, isConn),
|
|
54
59
|
method:
|
|
55
60
|
method.length > MAX_METHOD_LEN
|
|
56
61
|
? method.substring(0, MAX_METHOD_LEN)
|
|
@@ -335,13 +340,13 @@ function getCharset(headers) {
|
|
|
335
340
|
exports.handleRequest = function(req, res) {
|
|
336
341
|
var fullUrl = req.body.url;
|
|
337
342
|
if (!fullUrl || typeof fullUrl !== 'string') {
|
|
338
|
-
return res.json({ec:
|
|
343
|
+
return res.json({ec: 2, em: 'Invalid URL'});
|
|
339
344
|
}
|
|
340
345
|
|
|
341
346
|
fullUrl = common.encodeNonLatin1Char(fullUrl.replace(/#.*$/, ''));
|
|
342
347
|
var options = common.parseUrl(common.setProtocol(fullUrl));
|
|
343
348
|
if (!options.host) {
|
|
344
|
-
return res.json({ec:
|
|
349
|
+
return res.json({ec: 2, em: 'Invalid URL'});
|
|
345
350
|
}
|
|
346
351
|
var protocol = options.protocol;
|
|
347
352
|
if (protocol) {
|
|
@@ -386,7 +391,7 @@ exports.handleRequest = function(req, res) {
|
|
|
386
391
|
}
|
|
387
392
|
}
|
|
388
393
|
if (!req.body.noStore && req.body.needResponse && common.checkHistory(req.body)) {
|
|
389
|
-
handleComposerHistory(req.body);
|
|
394
|
+
handleComposerHistory(req.body, isConn);
|
|
390
395
|
dataCenter.saveData({
|
|
391
396
|
type: 'composer',
|
|
392
397
|
history: composerHistory
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var MAX_LENGTH = 800;
|
|
2
2
|
var MIN_LENGTH = 720;
|
|
3
|
-
var SIZE = 1024 *
|
|
3
|
+
var SIZE = 1024 * 512;
|
|
4
4
|
var COUNT = 100;
|
|
5
5
|
var logIndex = 0;
|
|
6
6
|
var logs = [];
|
|
@@ -45,40 +45,43 @@ function getLogs(startTime, count, logId) {
|
|
|
45
45
|
return sliceLogs(0, count, logId);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
function getLogIndex() {
|
|
49
|
+
++logIndex;
|
|
50
|
+
if (logIndex > 999999) {
|
|
51
|
+
logIndex = 0;
|
|
52
|
+
}
|
|
53
|
+
return logIndex;
|
|
54
|
+
}
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
exports.addLog = function set(log) {
|
|
57
|
+
if (!log) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
var now = Date.now();
|
|
62
|
+
var text = log.text;
|
|
63
|
+
if (text == null) {
|
|
64
|
+
text = '';
|
|
65
|
+
} else if (typeof text != 'string') {
|
|
66
|
+
text += '';
|
|
67
|
+
}
|
|
68
|
+
var overflow = text.length - SIZE;
|
|
69
|
+
logs.push({
|
|
70
|
+
id: now + '-' + getLogIndex(),
|
|
71
|
+
logId: log.id,
|
|
72
|
+
date: (log.t && parseInt(log.t, 10)) || now,
|
|
73
|
+
level: LEVEL_RE.test(log.level)
|
|
67
74
|
? log.level
|
|
68
75
|
: 'info',
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
proxy.getLatestId = function () {
|
|
81
|
-
var last = logs[logs.length - 1];
|
|
82
|
-
return last && last.id;
|
|
83
|
-
};
|
|
76
|
+
text: overflow > 9 ? text.substring(0, SIZE) + '...(' + overflow + ')' : text
|
|
77
|
+
});
|
|
78
|
+
var len = logs.length;
|
|
79
|
+
if (len > MAX_LENGTH) {
|
|
80
|
+
logs = logs.slice(len - MIN_LENGTH, len);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
exports.getLogs = getLogs;
|
|
84
|
+
exports.getLatestId = function () {
|
|
85
|
+
var last = logs[logs.length - 1];
|
|
86
|
+
return last && last.id;
|
|
84
87
|
};
|
package/lib/service/index.js
CHANGED
|
@@ -170,9 +170,7 @@ var saveData = function(type, data) {
|
|
|
170
170
|
method: 'POST',
|
|
171
171
|
url: 'http://127.0.0.1:' + curOptions.port + '/cgi-bin/service/save',
|
|
172
172
|
strictMode: true,
|
|
173
|
-
headers: {
|
|
174
|
-
'content-type': 'application/json'
|
|
175
|
-
},
|
|
173
|
+
headers: { 'content-type': 'application/json' },
|
|
176
174
|
body: body
|
|
177
175
|
}, function (err) {
|
|
178
176
|
if (err) {
|
|
@@ -213,7 +211,7 @@ function sendData() {
|
|
|
213
211
|
});
|
|
214
212
|
}
|
|
215
213
|
|
|
216
|
-
process.
|
|
214
|
+
process.on('whistleStarted', sendData);
|
|
217
215
|
|
|
218
216
|
module.exports = loadService;
|
|
219
217
|
|
package/lib/service/service.js
CHANGED
|
@@ -16,6 +16,7 @@ var composer = require('./composer');
|
|
|
16
16
|
var handleComposeData = require('./compose-data');
|
|
17
17
|
var Limiter = require('async-limiter');
|
|
18
18
|
var common = require('../util/common');
|
|
19
|
+
var logger = require('./console-log');
|
|
19
20
|
|
|
20
21
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';
|
|
21
22
|
|
|
@@ -26,21 +27,19 @@ var forwardRequest = dataCenter.forwardRequest;
|
|
|
26
27
|
|
|
27
28
|
var INSTALL_SCRIPT = path.join(__dirname, 'install.js');
|
|
28
29
|
var installChild;
|
|
29
|
-
|
|
30
|
+
var LOG_RE = /^(\d+)\r(fatal|error|warn|info|debug|log)\r([^\s]*)\r/;
|
|
30
31
|
var TEMP_PLUGINS_PATH = path.join(common.getWhistlePath(), '.temp_plugins');
|
|
31
32
|
var SESSIONS_FILE_RE = /\.(txt|json|saz)$/i;
|
|
32
33
|
var limiter = new Limiter({ concurrency: 10 });
|
|
33
34
|
var MAX_PLUGINS = 10;
|
|
34
|
-
var TEMP_FILES_PATH;
|
|
35
|
+
var TEMP_FILES_PATH = common.TEMP_FILES_PATH;
|
|
35
36
|
var SAVED_SESSIONS_PATH;
|
|
36
37
|
var LIMIT_SIZE = 1024 * 1024 * 128;
|
|
37
38
|
var MAX_TEMP_SIZE = 1024 * 1024 * 12;
|
|
38
39
|
var MAX_PLUGIN_SIZE = MAX_TEMP_SIZE;
|
|
39
40
|
var MAX_TEMP_PLUGINS_AGE = 1000 * 60 * 10; // 10 minutes
|
|
40
|
-
var TEMP_FILE_RE = /^[\da-f]{64}$/;
|
|
41
41
|
var CR = '\r';
|
|
42
42
|
var jsonParser = bodyParser.json({ limit: LIMIT_SIZE });
|
|
43
|
-
var urlencodedParser = bodyParser.urlencoded({ extended: true, limit: '1mb'});
|
|
44
43
|
var PLUGIN_SEP = /\s*,\s*/;
|
|
45
44
|
var config;
|
|
46
45
|
var curWhistleId;
|
|
@@ -48,7 +47,6 @@ var hasWhistleToken;
|
|
|
48
47
|
var whistleIdFile;
|
|
49
48
|
var storage = multer.memoryStorage();
|
|
50
49
|
var INVALID_NAME_RE = /[\u001e\u001f\u200e\u200f\u200d\u200c\u202a\u202d\u202e\u202c\u206e\u206f\u206b\u206a\u206d\u206c'<>:"\\/|?*]+/g;
|
|
51
|
-
var SPACE_RE = /\s+/g;
|
|
52
50
|
var upload = multer({
|
|
53
51
|
storage: storage,
|
|
54
52
|
fieldSize: LIMIT_SIZE
|
|
@@ -67,6 +65,19 @@ var ensureTempPluginsDir = function() {
|
|
|
67
65
|
|
|
68
66
|
ensureTempPluginsDir();
|
|
69
67
|
|
|
68
|
+
function parseLog(log) {
|
|
69
|
+
if (!log || typeof log !== 'string') {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
var match = LOG_RE.exec(log);
|
|
73
|
+
return match && {
|
|
74
|
+
t: match[1],
|
|
75
|
+
level: match[2],
|
|
76
|
+
id: match[3],
|
|
77
|
+
text: log.substring(match[0].length)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
70
81
|
process.on('data', function(data) {
|
|
71
82
|
if (data) {
|
|
72
83
|
if (data.type === 'whistleId') {
|
|
@@ -79,7 +90,7 @@ process.on('data', function(data) {
|
|
|
79
90
|
});
|
|
80
91
|
|
|
81
92
|
function getFilename(filename, time, count) {
|
|
82
|
-
filename = common.isString(filename) ? filename.replace(INVALID_NAME_RE, '').replace(
|
|
93
|
+
filename = common.isString(filename) ? filename.replace(INVALID_NAME_RE, '').replace(/\s+/g, ' ').substring(0, 64).trim() : '';
|
|
83
94
|
time = time || Date.now();
|
|
84
95
|
return common.getMonth(time) + '/' + filename + '_' + count + '_' + time;
|
|
85
96
|
}
|
|
@@ -96,7 +107,7 @@ function saveSessions(data, cb) {
|
|
|
96
107
|
return cb(err);
|
|
97
108
|
}
|
|
98
109
|
var filename = getFilename(data.filename, 0, count);
|
|
99
|
-
|
|
110
|
+
common.writeFile(path.join(SAVED_SESSIONS_PATH, filename), buf, function(e) {
|
|
100
111
|
!e && saveData({ type: 'savedData', filename: filename, buffer: buf } );
|
|
101
112
|
cb(e);
|
|
102
113
|
});
|
|
@@ -155,7 +166,8 @@ function getTempFiles(list, cb) {
|
|
|
155
166
|
}
|
|
156
167
|
};
|
|
157
168
|
list = list.forEach(function(filename) {
|
|
158
|
-
|
|
169
|
+
filename = common.getTempFile(filename);
|
|
170
|
+
if (!filename) {
|
|
159
171
|
return execCb();
|
|
160
172
|
}
|
|
161
173
|
filename = path.join(TEMP_FILES_PATH, filename);
|
|
@@ -182,7 +194,7 @@ function writeTempPlugin(plugin, data, cb) {
|
|
|
182
194
|
plugin = plugin.split('/').pop();
|
|
183
195
|
var tempPath = path.join(TEMP_PLUGINS_PATH, plugin);
|
|
184
196
|
ensureTempPluginsDir();
|
|
185
|
-
|
|
197
|
+
common.writeFile(tempPath, data, function(e) {
|
|
186
198
|
cb(e, e ? null : tempPath);
|
|
187
199
|
});
|
|
188
200
|
}
|
|
@@ -296,6 +308,10 @@ function sessionsHandler() {
|
|
|
296
308
|
function abort() {
|
|
297
309
|
res.destroy();
|
|
298
310
|
}
|
|
311
|
+
if (req.headers[common.WHISTLE_UID_HEADER] !== config.uid) {
|
|
312
|
+
return res.status(403).end('Forbidden');
|
|
313
|
+
}
|
|
314
|
+
delete req.headers[common.WHISTLE_UID_HEADER];
|
|
299
315
|
next();
|
|
300
316
|
});
|
|
301
317
|
app.get('/service/*', forwardRequest);
|
|
@@ -336,7 +352,7 @@ function sessionsHandler() {
|
|
|
336
352
|
} catch (e) {}
|
|
337
353
|
});
|
|
338
354
|
});
|
|
339
|
-
app.post('/cgi-bin/plugins/install',
|
|
355
|
+
app.post('/cgi-bin/plugins/install', bodyParser.urlencoded({ extended: true, limit: '1mb'}), function(req, res) {
|
|
340
356
|
var plugins = req.body.plugins;
|
|
341
357
|
var clientId = req.body.clientId;
|
|
342
358
|
plugins = common.isString(plugins) ? plugins.trim().split(PLUGIN_SEP) : null;
|
|
@@ -444,8 +460,9 @@ function sessionsHandler() {
|
|
|
444
460
|
});
|
|
445
461
|
}
|
|
446
462
|
var filename = req.query.filename;
|
|
447
|
-
|
|
448
|
-
|
|
463
|
+
var tempFile = common.getTempFile(filename);
|
|
464
|
+
if (tempFile) {
|
|
465
|
+
filename = path.join(TEMP_FILES_PATH, tempFile);
|
|
449
466
|
}
|
|
450
467
|
getFile(filename, function(em, data) {
|
|
451
468
|
if (em) {
|
|
@@ -458,7 +475,7 @@ function sessionsHandler() {
|
|
|
458
475
|
app.use('/cgi-bin/temp/create',
|
|
459
476
|
jsonParser,
|
|
460
477
|
function(req, res) {
|
|
461
|
-
|
|
478
|
+
common.writeTempFile(getContent(req.body), function(e, filename) {
|
|
462
479
|
if (e) {
|
|
463
480
|
return res.json({ ec: 2, em: e.message });
|
|
464
481
|
}
|
|
@@ -491,8 +508,12 @@ function sessionsHandler() {
|
|
|
491
508
|
}
|
|
492
509
|
}
|
|
493
510
|
);
|
|
511
|
+
app.use('/cgi-bin/log/set', function(req, _, next) {
|
|
512
|
+
req.headers['content-type'] = 'application/json';
|
|
513
|
+
next();
|
|
514
|
+
});
|
|
494
515
|
app.use(bodyParser.urlencoded({ extended: true, limit: LIMIT_SIZE }));
|
|
495
|
-
app.use(
|
|
516
|
+
app.use(jsonParser);
|
|
496
517
|
app.use('/cgi-bin/sessions/export', function (req, res) {
|
|
497
518
|
var body = req.body;
|
|
498
519
|
var type = body.exportFileType;
|
|
@@ -509,6 +530,35 @@ function sessionsHandler() {
|
|
|
509
530
|
download(body);
|
|
510
531
|
});
|
|
511
532
|
});
|
|
533
|
+
|
|
534
|
+
app.use('/cgi-bin/log/set', function(req, res) {
|
|
535
|
+
res.setHeader('content-type', 'image/png');
|
|
536
|
+
if (req.method === 'POST') {
|
|
537
|
+
var list = req.body.list;
|
|
538
|
+
if (Array.isArray(list)) {
|
|
539
|
+
var len = Math.min(list.length, 20);
|
|
540
|
+
for (var i = 0; i < len; i++) {
|
|
541
|
+
logger.addLog(parseLog(list[i]));
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
} else {
|
|
545
|
+
logger.addLog(req.query);
|
|
546
|
+
}
|
|
547
|
+
res.end();
|
|
548
|
+
});
|
|
549
|
+
app.use('/cgi-bin/log/get', function(req, res) {
|
|
550
|
+
var query = req.query;
|
|
551
|
+
var startLogTime = query.startLogTime;
|
|
552
|
+
var init = startLogTime == -4;
|
|
553
|
+
var stopRecordConsole = startLogTime == -3;
|
|
554
|
+
var curLogId = logger.getLatestId();
|
|
555
|
+
common.sendGzip(req, res, {
|
|
556
|
+
ec: 0,
|
|
557
|
+
log: init || stopRecordConsole ? [] : logger.getLogs(startLogTime, query.count, query.logId),
|
|
558
|
+
curLogId: stopRecordConsole ? undefined : curLogId,
|
|
559
|
+
lastLogId: init ? (curLogId || -2) : (stopRecordConsole ? curLogId : undefined)
|
|
560
|
+
});
|
|
561
|
+
});
|
|
512
562
|
return app;
|
|
513
563
|
}
|
|
514
564
|
|
|
@@ -564,7 +614,6 @@ function checkWhistleId(cb) {
|
|
|
564
614
|
module.exports = function (options, callback) {
|
|
565
615
|
config = options;
|
|
566
616
|
whistleIdFile = path.join(options.baseDir, options.storage || '', '.whistle_id');
|
|
567
|
-
TEMP_FILES_PATH = options.TEMP_FILES_PATH;
|
|
568
617
|
SAVED_SESSIONS_PATH = options.SAVED_SESSIONS_PATH;
|
|
569
618
|
dataCenter.setup(options);
|
|
570
619
|
composer.setup(options);
|
package/lib/service/util.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
var crypto = require('crypto');
|
|
2
1
|
var path = require('path');
|
|
3
2
|
var fs = require('fs');
|
|
4
|
-
var fse = require('fs-extra2');
|
|
5
3
|
var zlib = require('../util/zlib');
|
|
6
4
|
var common = require('../util/common');
|
|
7
5
|
|
|
@@ -426,16 +424,6 @@ function parseFrames(res, content, callback) {
|
|
|
426
424
|
|
|
427
425
|
exports.parseFrames = parseFrames;
|
|
428
426
|
|
|
429
|
-
function getHexHash(ctn, key) {
|
|
430
|
-
return crypto
|
|
431
|
-
.createHmac('sha256', key || 'whistle_temp_files')
|
|
432
|
-
.update(ctn || '').digest('hex').toLowerCase();
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
function descSorter(a, b) {
|
|
436
|
-
return a > b ? -1 : 1;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
427
|
var MAX_SESSIONS_FILES = 2000;
|
|
440
428
|
var SAVED_SESSIONS_FILE_RE = /_([1-9]\d*)_(\d+)$/;
|
|
441
429
|
var DIR_RE = /^\d{6}$/;
|
|
@@ -492,7 +480,9 @@ exports.getSavedList = function(savedDir, cb) {
|
|
|
492
480
|
list.push(dir);
|
|
493
481
|
}
|
|
494
482
|
});
|
|
495
|
-
list = list.sort(
|
|
483
|
+
list = list.sort(function (a, b) {
|
|
484
|
+
return a > b ? -1 : 1;
|
|
485
|
+
}).slice(0, 12).map(function(dir) {
|
|
496
486
|
return path.join(savedDir, dir);
|
|
497
487
|
});
|
|
498
488
|
readSessionsFiles(list, cb);
|
|
@@ -504,32 +494,3 @@ var SHARE_TYPE_RE = /Share$/;
|
|
|
504
494
|
exports.isShareType = function(type) {
|
|
505
495
|
return SHARE_TYPE_RE.test(type);
|
|
506
496
|
};
|
|
507
|
-
|
|
508
|
-
function writeRetry(filepath, data, callback, retry) {
|
|
509
|
-
fse.outputFile(filepath, data, function(e) {
|
|
510
|
-
if (!e || retry) {
|
|
511
|
-
return callback(e);
|
|
512
|
-
}
|
|
513
|
-
writeRetry(filepath, data, callback, true);
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
function writeFile(filepath, data, callback) {
|
|
518
|
-
common.getStat(filepath, function(_, stat) {
|
|
519
|
-
if (!stat || !stat.isFile()) {
|
|
520
|
-
return writeRetry(filepath, data, callback);
|
|
521
|
-
}
|
|
522
|
-
callback();
|
|
523
|
-
});
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
exports.writeFile = writeFile;
|
|
527
|
-
|
|
528
|
-
function writeTempFile(dir, value, callback) {
|
|
529
|
-
var filename = getHexHash(value);
|
|
530
|
-
writeFile(path.join(dir, filename), value, function(err) {
|
|
531
|
-
callback(err, filename);
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
exports.writeTempFile = writeTempFile;
|
package/lib/socket-mgr.js
CHANGED
|
@@ -7,28 +7,14 @@ var extend = require('extend');
|
|
|
7
7
|
var pendingReqList = [];
|
|
8
8
|
var INTERVAL = 22 * 1000;
|
|
9
9
|
var proxy;
|
|
10
|
-
var index = 0;
|
|
11
|
-
var MAX_PAYLOAD = 1024 * 1024;
|
|
12
10
|
var conns = {};
|
|
13
11
|
var PING = Buffer.from('iQA=', 'base64');
|
|
14
12
|
var PONG = Buffer.from('ioAn6ubf', 'base64');
|
|
15
13
|
var PAUSE_STATUS = 1;
|
|
16
14
|
var IGNORE_STATUS = 2;
|
|
17
15
|
var MAX_COMPOSE_FRAME_COUNT = 5;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
++index;
|
|
21
|
-
if (index > 999) {
|
|
22
|
-
index = 0;
|
|
23
|
-
}
|
|
24
|
-
if (index > 99) {
|
|
25
|
-
return Date.now() + '-' + index;
|
|
26
|
-
}
|
|
27
|
-
if (index > 9) {
|
|
28
|
-
return Date.now() + '-0' + index;
|
|
29
|
-
}
|
|
30
|
-
return Date.now() + '-00' + index;
|
|
31
|
-
}
|
|
16
|
+
var getFrameId = util.getFrameId;
|
|
17
|
+
var MAX_PAYLOAD = util.MAX_FRAME_PAYLOAD;
|
|
32
18
|
|
|
33
19
|
exports = module.exports = function (p) {
|
|
34
20
|
proxy = p;
|
package/lib/tunnel.js
CHANGED
|
@@ -47,8 +47,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
47
47
|
var headers = req.headers;
|
|
48
48
|
if (headers[config.WEBUI_HEAD]) {
|
|
49
49
|
delete headers[config.WEBUI_HEAD];
|
|
50
|
-
reqSocket.destroy();
|
|
51
|
-
return;
|
|
50
|
+
return reqSocket.destroy();
|
|
52
51
|
}
|
|
53
52
|
req.fromHttpServer = reqSocket.fromHttpServer = fromHttpServer;
|
|
54
53
|
req.fromHttpsServer = reqSocket.fromHttpsServer = fromHttpsServer;
|
|
@@ -83,8 +82,7 @@ function tunnelProxy(server, proxy, type) {
|
|
|
83
82
|
var clientInfo = util.parseClientInfo(req);
|
|
84
83
|
reqSocket._disabledProxyRules = req._disabledProxyRules;
|
|
85
84
|
reqSocket.clientIp = req.clientIp = util.getClientIp(req, clientInfo[0]);
|
|
86
|
-
reqSocket.clientPort = req.clientPort =
|
|
87
|
-
clientInfo[1] || util.getClientPort(req);
|
|
85
|
+
reqSocket.clientPort = req.clientPort = clientInfo[1] || util.getClientPort(req);
|
|
88
86
|
req._remoteAddr = clientInfo[2] || util.getRemoteAddr(req);
|
|
89
87
|
req._remotePort = clientInfo[3] || util.getRemotePort(req);
|
|
90
88
|
delete headers[config.CLIENT_PORT_HEADER];
|
package/lib/upgrade.js
CHANGED
|
@@ -105,7 +105,7 @@ function upgradeHandler(req, socket) {
|
|
|
105
105
|
util.addTunnelData(socket, headers);
|
|
106
106
|
socket._clientId = util.getComposerClientId(headers);
|
|
107
107
|
var getBuffer = function (method, newHeaders, path) {
|
|
108
|
-
var rawData = (method || 'GET') + ' ' + (path || socket.url || req.url) + '
|
|
108
|
+
var rawData = (method || 'GET') + ' ' + (path || socket.url || req.url) + ' HTTP/1.1';
|
|
109
109
|
newHeaders = formatHeaders(newHeaders || headers, req.rawHeaders);
|
|
110
110
|
if (newHeaders = getRawHeaders(newHeaders)) {
|
|
111
111
|
rawData += '\r\n' + newHeaders;
|
package/lib/util/common.js
CHANGED
|
@@ -67,7 +67,81 @@ var PATH_SEP_RE = /[\\/]/;
|
|
|
67
67
|
var CUR_PATH_RE = /^\.[\\/]/;
|
|
68
68
|
var CLIENT_PORT_HEADER = 'x-whistle-client-port';
|
|
69
69
|
var ALLOW_ACK = 'x-whistle-allow-tunnel-ack';
|
|
70
|
+
var PLUS_RE = /\+/g;
|
|
71
|
+
var TOKEN = '\r\u0000\n\u0003\r';
|
|
72
|
+
var PROP_SEP_RE = /(\\*)([|&]|\\[stnrfv])/g;
|
|
73
|
+
var TEMP_FILE_RE = /^(?:\/?temp\/)?([\da-f]{64})(?:\.[\w.-]+)?$/;
|
|
74
|
+
var TEMP_FILES_PATH = path.join(getWhistlePath(), 'temp_files');
|
|
70
75
|
|
|
76
|
+
|
|
77
|
+
exports.WHISTLE_UID_HEADER = '_x-whistle-uid_';
|
|
78
|
+
|
|
79
|
+
exports.getTempFile = function(str) {
|
|
80
|
+
var match = TEMP_FILE_RE.exec(str);
|
|
81
|
+
return match && match[1];
|
|
82
|
+
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
var PROPS_CHAR = {
|
|
86
|
+
s: ' ',
|
|
87
|
+
t: '\t',
|
|
88
|
+
n: '\n',
|
|
89
|
+
r: '\r',
|
|
90
|
+
f: '\f',
|
|
91
|
+
v: '\v'
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
function replaceToken(s, val) {
|
|
95
|
+
return s.split(TOKEN).join(val);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
exports.parseProps = function(str) {
|
|
99
|
+
return str.replace(PROP_SEP_RE, function(_, slash, val) {
|
|
100
|
+
var isChar = val.length > 1;
|
|
101
|
+
if (isChar) {
|
|
102
|
+
slash += '/';
|
|
103
|
+
val = val.substring(1);
|
|
104
|
+
} else if (!slash) {
|
|
105
|
+
return TOKEN;
|
|
106
|
+
}
|
|
107
|
+
var len = slash.length;
|
|
108
|
+
slash = slash.substring(0, Math.floor(len / 2));
|
|
109
|
+
if (isChar) {
|
|
110
|
+
return slash + (len % 2 ? PROPS_CHAR[val] : val);
|
|
111
|
+
}
|
|
112
|
+
return slash + (len % 2 ? val : TOKEN);
|
|
113
|
+
}).split(TOKEN);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
var decoder = {
|
|
117
|
+
decodeURIComponent: function (s) {
|
|
118
|
+
s = replaceToken(s, '+');
|
|
119
|
+
return qs.unescape(s);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
var rawDecoder = {
|
|
123
|
+
decodeURIComponent: function (s) {
|
|
124
|
+
return replaceToken(s, '+');
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
var rawDecoder2 = {
|
|
128
|
+
decodeURIComponent: function (s) {
|
|
129
|
+
return s;
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
exports.parseQuery = function (str, sep, eq, escape) {
|
|
134
|
+
try {
|
|
135
|
+
if (str.indexOf('+') === -1 || str.indexOf(TOKEN) !== -1) {
|
|
136
|
+
return qs.parse(str, sep, eq, escape ? rawDecoder2 : undefined);
|
|
137
|
+
}
|
|
138
|
+
str = str.replace(PLUS_RE, TOKEN);
|
|
139
|
+
return qs.parse(str, sep, eq, escape ? rawDecoder : decoder);
|
|
140
|
+
} catch (e) {}
|
|
141
|
+
return '';
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
exports.TEMP_FILES_PATH = TEMP_FILES_PATH;
|
|
71
145
|
exports.ALLOW_ACK = ALLOW_ACK;
|
|
72
146
|
exports.CONN_TIMEOUT = CONN_TIMEOUT;
|
|
73
147
|
exports.TGZ_FILE_NAME_RE = /^(?:[\w.~-]+-)?whistle\.[a-z\d_-]+-\d+\.\d+\.\d+[\w.-]*\.(?:tgz|tar(?:\.gz)?)$/;
|
|
@@ -414,14 +488,8 @@ exports.isConnect = function(options) {
|
|
|
414
488
|
);
|
|
415
489
|
};
|
|
416
490
|
|
|
417
|
-
var NO_PROTO_RE = /[^a-zA-Z0-9.-]/;
|
|
418
|
-
|
|
419
491
|
function hasProtocol(url) {
|
|
420
|
-
|
|
421
|
-
if (index <= 0) {
|
|
422
|
-
return false;
|
|
423
|
-
}
|
|
424
|
-
return !NO_PROTO_RE.test(url.substring(0, index));
|
|
492
|
+
return /^[a-zA-Z0-9.-]+:\/\//.test(url);
|
|
425
493
|
}
|
|
426
494
|
|
|
427
495
|
function setProtocol(url, isHttps) {
|
|
@@ -894,7 +962,6 @@ var DIG_RE = /^([+-]?)([1-9]\d{0,15})$/;
|
|
|
894
962
|
var NUM_RE = /^(?:0|[1-9]\d*)$/;
|
|
895
963
|
var ARR_RE = /\[(0|[1-8]\d{0,15}|9\d{0,14})\]$/;
|
|
896
964
|
var DOT_RE = /(\\+)\./g;
|
|
897
|
-
var CR_RE = /\r/g;
|
|
898
965
|
|
|
899
966
|
function isString(str) {
|
|
900
967
|
return str && typeof str === 'string';
|
|
@@ -963,12 +1030,6 @@ function parseKey(key) {
|
|
|
963
1030
|
return list;
|
|
964
1031
|
}
|
|
965
1032
|
|
|
966
|
-
function replaceDot(_, slash) {
|
|
967
|
-
var len = slash.length;
|
|
968
|
-
slash = slash.substring(0, Math.floor(len / 2));
|
|
969
|
-
return slash + (len % 2 ? '\r' : '.');
|
|
970
|
-
}
|
|
971
|
-
|
|
972
1033
|
function parseKeys(key) {
|
|
973
1034
|
if (!isString(key)) {
|
|
974
1035
|
return key;
|
|
@@ -977,13 +1038,17 @@ function parseKeys(key) {
|
|
|
977
1038
|
if (key.indexOf('.') === -1) {
|
|
978
1039
|
return parseKey(key);
|
|
979
1040
|
}
|
|
980
|
-
key = key.replace(DOT_RE,
|
|
1041
|
+
key = key.replace(DOT_RE, function (_, slash) {
|
|
1042
|
+
var len = slash.length;
|
|
1043
|
+
slash = slash.substring(0, Math.floor(len / 2));
|
|
1044
|
+
return slash + (len % 2 ? TOKEN : '.');
|
|
1045
|
+
});
|
|
981
1046
|
if (key.indexOf('.') === -1) {
|
|
982
|
-
return parseKey(key
|
|
1047
|
+
return parseKey(replaceToken(key, '.'));
|
|
983
1048
|
}
|
|
984
1049
|
var result = [];
|
|
985
1050
|
key.split('.').forEach(function(k) {
|
|
986
|
-
k = parseKey(k.trim()
|
|
1051
|
+
k = parseKey(replaceToken(k.trim(), '.'));
|
|
987
1052
|
if (Array.isArray(k)) {
|
|
988
1053
|
result = result.concat(k);
|
|
989
1054
|
} else {
|
|
@@ -1937,3 +2002,36 @@ exports.getSessionInfo = function(headers) {
|
|
|
1937
2002
|
result._ = rawResult;
|
|
1938
2003
|
return result;
|
|
1939
2004
|
};
|
|
2005
|
+
|
|
2006
|
+
function writeRetry(filepath, data, callback, retry) {
|
|
2007
|
+
fse.outputFile(filepath, data, function(e) {
|
|
2008
|
+
if (!e || retry) {
|
|
2009
|
+
return callback(e);
|
|
2010
|
+
}
|
|
2011
|
+
writeRetry(filepath, data, callback, true);
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
function writeFile(filepath, data, callback) {
|
|
2016
|
+
getStat(filepath, function(_, stat) {
|
|
2017
|
+
if (!stat || !stat.isFile()) {
|
|
2018
|
+
return writeRetry(filepath, data, callback);
|
|
2019
|
+
}
|
|
2020
|
+
callback();
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
exports.writeFile = writeFile;
|
|
2025
|
+
|
|
2026
|
+
function getHexHash(ctn, key) {
|
|
2027
|
+
return crypto
|
|
2028
|
+
.createHmac('sha256', key || 'whistle_temp_files')
|
|
2029
|
+
.update(ctn || '').digest('hex').toLowerCase();
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
exports.writeTempFile = function (value, callback) {
|
|
2033
|
+
var filename = getHexHash(value);
|
|
2034
|
+
writeFile(path.join(TEMP_FILES_PATH, filename), value, function(err) {
|
|
2035
|
+
callback(err, filename);
|
|
2036
|
+
});
|
|
2037
|
+
};
|