whistle 2.10.2 → 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.
@@ -32,7 +32,7 @@ var TEMP_PLUGINS_PATH = path.join(common.getWhistlePath(), '.temp_plugins');
32
32
  var SESSIONS_FILE_RE = /\.(txt|json|saz)$/i;
33
33
  var limiter = new Limiter({ concurrency: 10 });
34
34
  var MAX_PLUGINS = 10;
35
- var TEMP_FILES_PATH;
35
+ var TEMP_FILES_PATH = common.TEMP_FILES_PATH;
36
36
  var SAVED_SESSIONS_PATH;
37
37
  var LIMIT_SIZE = 1024 * 1024 * 128;
38
38
  var MAX_TEMP_SIZE = 1024 * 1024 * 12;
@@ -47,7 +47,6 @@ var hasWhistleToken;
47
47
  var whistleIdFile;
48
48
  var storage = multer.memoryStorage();
49
49
  var INVALID_NAME_RE = /[\u001e\u001f\u200e\u200f\u200d\u200c\u202a\u202d\u202e\u202c\u206e\u206f\u206b\u206a\u206d\u206c'<>:"\\/|?*]+/g;
50
- var SPACE_RE = /\s+/g;
51
50
  var upload = multer({
52
51
  storage: storage,
53
52
  fieldSize: LIMIT_SIZE
@@ -91,7 +90,7 @@ process.on('data', function(data) {
91
90
  });
92
91
 
93
92
  function getFilename(filename, time, count) {
94
- filename = common.isString(filename) ? filename.replace(INVALID_NAME_RE, '').replace(SPACE_RE, ' ').substring(0, 64).trim() : '';
93
+ filename = common.isString(filename) ? filename.replace(INVALID_NAME_RE, '').replace(/\s+/g, ' ').substring(0, 64).trim() : '';
95
94
  time = time || Date.now();
96
95
  return common.getMonth(time) + '/' + filename + '_' + count + '_' + time;
97
96
  }
@@ -108,7 +107,7 @@ function saveSessions(data, cb) {
108
107
  return cb(err);
109
108
  }
110
109
  var filename = getFilename(data.filename, 0, count);
111
- util.writeFile(path.join(SAVED_SESSIONS_PATH, filename), buf, function(e) {
110
+ common.writeFile(path.join(SAVED_SESSIONS_PATH, filename), buf, function(e) {
112
111
  !e && saveData({ type: 'savedData', filename: filename, buffer: buf } );
113
112
  cb(e);
114
113
  });
@@ -167,7 +166,8 @@ function getTempFiles(list, cb) {
167
166
  }
168
167
  };
169
168
  list = list.forEach(function(filename) {
170
- if (!common.isTempFile(filename)) {
169
+ filename = common.getTempFile(filename);
170
+ if (!filename) {
171
171
  return execCb();
172
172
  }
173
173
  filename = path.join(TEMP_FILES_PATH, filename);
@@ -194,7 +194,7 @@ function writeTempPlugin(plugin, data, cb) {
194
194
  plugin = plugin.split('/').pop();
195
195
  var tempPath = path.join(TEMP_PLUGINS_PATH, plugin);
196
196
  ensureTempPluginsDir();
197
- util.writeFile(tempPath, data, function(e) {
197
+ common.writeFile(tempPath, data, function(e) {
198
198
  cb(e, e ? null : tempPath);
199
199
  });
200
200
  }
@@ -308,6 +308,10 @@ function sessionsHandler() {
308
308
  function abort() {
309
309
  res.destroy();
310
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];
311
315
  next();
312
316
  });
313
317
  app.get('/service/*', forwardRequest);
@@ -456,8 +460,9 @@ function sessionsHandler() {
456
460
  });
457
461
  }
458
462
  var filename = req.query.filename;
459
- if (common.isTempFile(filename)) {
460
- filename = path.join(TEMP_FILES_PATH, filename);
463
+ var tempFile = common.getTempFile(filename);
464
+ if (tempFile) {
465
+ filename = path.join(TEMP_FILES_PATH, tempFile);
461
466
  }
462
467
  getFile(filename, function(em, data) {
463
468
  if (em) {
@@ -470,7 +475,7 @@ function sessionsHandler() {
470
475
  app.use('/cgi-bin/temp/create',
471
476
  jsonParser,
472
477
  function(req, res) {
473
- util.writeTempFile(TEMP_FILES_PATH, getContent(req.body), function(e, filename) {
478
+ common.writeTempFile(getContent(req.body), function(e, filename) {
474
479
  if (e) {
475
480
  return res.json({ ec: 2, em: e.message });
476
481
  }
@@ -609,7 +614,6 @@ function checkWhistleId(cb) {
609
614
  module.exports = function (options, callback) {
610
615
  config = options;
611
616
  whistleIdFile = path.join(options.baseDir, options.storage || '', '.whistle_id');
612
- TEMP_FILES_PATH = options.TEMP_FILES_PATH;
613
617
  SAVED_SESSIONS_PATH = options.SAVED_SESSIONS_PATH;
614
618
  dataCenter.setup(options);
615
619
  composer.setup(options);
@@ -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(descSorter).slice(0, 12).map(function(dir) {
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
- function getFrameId() {
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;
@@ -70,10 +70,16 @@ var ALLOW_ACK = 'x-whistle-allow-tunnel-ack';
70
70
  var PLUS_RE = /\+/g;
71
71
  var TOKEN = '\r\u0000\n\u0003\r';
72
72
  var PROP_SEP_RE = /(\\*)([|&]|\\[stnrfv])/g;
73
- var TEMP_FILE_RE = /^[\da-f]{64}$/;
73
+ var TEMP_FILE_RE = /^(?:\/?temp\/)?([\da-f]{64})(?:\.[\w.-]+)?$/;
74
+ var TEMP_FILES_PATH = path.join(getWhistlePath(), 'temp_files');
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];
74
82
 
75
- exports.isTempFile = function(str) {
76
- return TEMP_FILE_RE.test(str);
77
83
  };
78
84
 
79
85
  var PROPS_CHAR = {
@@ -135,6 +141,7 @@ exports.parseQuery = function (str, sep, eq, escape) {
135
141
  return '';
136
142
  };
137
143
 
144
+ exports.TEMP_FILES_PATH = TEMP_FILES_PATH;
138
145
  exports.ALLOW_ACK = ALLOW_ACK;
139
146
  exports.CONN_TIMEOUT = CONN_TIMEOUT;
140
147
  exports.TGZ_FILE_NAME_RE = /^(?:[\w.~-]+-)?whistle\.[a-z\d_-]+-\d+\.\d+\.\d+[\w.-]*\.(?:tgz|tar(?:\.gz)?)$/;
@@ -481,14 +488,8 @@ exports.isConnect = function(options) {
481
488
  );
482
489
  };
483
490
 
484
- var NO_PROTO_RE = /[^a-zA-Z0-9.-]/;
485
-
486
491
  function hasProtocol(url) {
487
- var index = isString(url) ? url.indexOf('://') : -1;
488
- if (index <= 0) {
489
- return false;
490
- }
491
- return !NO_PROTO_RE.test(url.substring(0, index));
492
+ return /^[a-zA-Z0-9.-]+:\/\//.test(url);
492
493
  }
493
494
 
494
495
  function setProtocol(url, isHttps) {
@@ -2001,3 +2002,36 @@ exports.getSessionInfo = function(headers) {
2001
2002
  result._ = rawResult;
2002
2003
  return result;
2003
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
+ };
package/lib/util/index.js CHANGED
@@ -1164,7 +1164,7 @@ function getTempFilePath(filePath, rule) {
1164
1164
  var root = rule.root;
1165
1165
  if (!root && common.TEMP_PATH_RE.test(filePath)) {
1166
1166
  rule._suffix = RegExp.$2;
1167
- return path.join(config.TEMP_FILES_PATH, RegExp.$1);
1167
+ return path.join(common.TEMP_FILES_PATH, RegExp.$1);
1168
1168
  }
1169
1169
  return joinPath(root, decodePath(filePath));
1170
1170
  }
@@ -3102,10 +3102,10 @@ function getCookieItem(name, cookie) {
3102
3102
  if (!cookie || typeof cookie != 'object') {
3103
3103
  return name + '=' + (cookie == null ? '' : cookie);
3104
3104
  }
3105
- var attrs = [name + '=' + escapeValue(cookie.value)];
3105
+ var attrs = [name + '=' + escapeValue(cookie.value || cookie.Value)];
3106
3106
  var maxAge = cookie.maxAge || cookie.maxage ||
3107
3107
  cookie.MaxAge || cookie['Max-Age'] || cookie['max-age'];
3108
- maxAge = parseInt(cookie.maxAge, 10);
3108
+ maxAge = parseInt(maxAge, 10);
3109
3109
  if (!Number.isNaN(maxAge)) {
3110
3110
  attrs.push('Expires=' + new Date(Date.now() + maxAge * 1000).toGMTString());
3111
3111
  attrs.push('Max-Age=' + (maxAge === EXPIRED_SEC ? 0 : maxAge));
@@ -3638,7 +3638,8 @@ function formatAuth(obj) {
3638
3638
  var password = obj.password;
3639
3639
  return {
3640
3640
  username: username == null ? null : String(username),
3641
- password: password == null ? null : String(password)
3641
+ password: password == null ? null : String(password),
3642
+ proxy: !!obj.proxy
3642
3643
  };
3643
3644
  }
3644
3645
 
@@ -3997,3 +3998,22 @@ exports.isHide = function(req) {
3997
3998
  var d = req.disable || '';
3998
3999
  return req.fromComposer ? checkHideProp(e, d, 'Composer') : checkHideProp(e, d, '', req._filters && req._filters.hide);
3999
4000
  };
4001
+
4002
+
4003
+ var frameIndex = 0;
4004
+
4005
+ exports.MAX_FRAME_PAYLOAD = 1024 * 1024;
4006
+
4007
+ exports.getFrameId = function() {
4008
+ ++frameIndex;
4009
+ if (frameIndex > 999) {
4010
+ frameIndex = 0;
4011
+ }
4012
+ if (frameIndex > 99) {
4013
+ return Date.now() + '-' + frameIndex;
4014
+ }
4015
+ if (frameIndex > 9) {
4016
+ return Date.now() + '-0' + frameIndex;
4017
+ }
4018
+ return Date.now() + '-00' + frameIndex;
4019
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "whistle",
3
3
  "description": "HTTP, HTTP2, HTTPS, Websocket debugging proxy",
4
- "version": "2.10.2",
4
+ "version": "2.10.3",
5
5
  "dataDirname": ".whistle",
6
6
  "localUIHost": "local.whistlejs.com",
7
7
  "port": 8899,
@@ -53,7 +53,7 @@
53
53
  "parseurl": "^1.3.1",
54
54
  "pfork": "^0.6.3",
55
55
  "pipestream": "^0.7.5",
56
- "set-global-proxy": "^0.3.0",
56
+ "set-global-proxy": "^0.4.0",
57
57
  "sni": "1.0.0",
58
58
  "sockx": "^0.2.3",
59
59
  "starting": "^8.0.3",
@@ -1,37 +0,0 @@
1
- var util = require('../../../lib/util');
2
- var loadService = require('../lib/proxy').loadService;
3
-
4
- var MAX_LEN = 1024 * 1024 * 6;
5
- var HTTP_RE = /https?:\/\/\S/i;
6
-
7
- module.exports = function(req, res) {
8
- var url = req.query.url;
9
- if (HTTP_RE.test(url)) {
10
- util.request({
11
- url: url,
12
- maxLength: MAX_LEN
13
- }, function(err, body, r) {
14
- if (err) {
15
- var msg = err.code === 'EEXCEED' ? 'The size of response body exceeds 6MB' : err.message;
16
- return res.json({ec: 2, em: msg});
17
- }
18
- var status = r.statusCode;
19
- if (status !== 200) {
20
- var em = status > 200 && status < 400 ? 'No data' : 'Request failed';
21
- return res.json({ec: 2, em: em + ' (statusCode: ' + status + ')'});
22
- }
23
- return res.json({ec: 0, body: body});
24
- });
25
- } else if (util.isString(url)) {
26
- loadService(function(err, options) {
27
- if (err) {
28
- util.sendRes(res, 500, err.stack || err);
29
- } else {
30
- req.url = '/cgi-bin/temp/get?filename=' + encodeURIComponent(url);
31
- util.transformReq(req, res, options.port);
32
- }
33
- });
34
- } else {
35
- res.json({ec: 400, em: 'Bad url'});
36
- }
37
- };