whistle 2.9.14 → 2.9.15-beta
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/bin/ca/cli.js +95 -0
- package/bin/ca/index.d.ts +1 -0
- package/bin/ca/index.js +43 -0
- package/bin/proxy/cli.js +17 -17
- package/bin/util.js +19 -2
- package/bin/whistle.js +22 -3
- package/biz/webui/htdocs/index.html +1 -1
- package/biz/webui/htdocs/js/index.js +1 -1
- package/lib/config.js +6 -9
- package/lib/util/is-utf8.js +1 -1
- package/package.json +1 -1
package/bin/ca/cli.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
var net = require('net');
|
|
2
|
+
var fs = require('fs');
|
|
3
|
+
var path = require('path');
|
|
4
|
+
var installRootCA = require('./index');
|
|
5
|
+
var util = require('../util');
|
|
6
|
+
var fileMgr = require('../../lib/util/file-mgr');
|
|
7
|
+
var httpMgr = require('../../lib/util/http-mgr');
|
|
8
|
+
var commonUtil = require('../../lib/util/common');
|
|
9
|
+
var config = require('../../lib/config');
|
|
10
|
+
|
|
11
|
+
var NUM_RE = /^\d+$/;
|
|
12
|
+
var HOST_SUFFIX_RE = /\:(\d+|auto)?$/;
|
|
13
|
+
var HOST_RE = /^[a-z\d_-]+(?:\.[a-z\d_-]+)*$/i;
|
|
14
|
+
var URL_RE = /^https?:\/\/./i;
|
|
15
|
+
var MAX_LEN = 1024 * 1024;
|
|
16
|
+
|
|
17
|
+
function installCert(certFile, url) {
|
|
18
|
+
try {
|
|
19
|
+
installRootCA(fileMgr.convertSlash(certFile));
|
|
20
|
+
util.info('Install root CA (' + (url || certFile) + ') successful.');
|
|
21
|
+
} catch (e) {
|
|
22
|
+
util.error(e.message);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function install(addr) {
|
|
27
|
+
if (addr.file) {
|
|
28
|
+
return installCert(addr.file);
|
|
29
|
+
}
|
|
30
|
+
addr.needRawData = true;
|
|
31
|
+
addr.maxLength = MAX_LEN;
|
|
32
|
+
addr.headers = {
|
|
33
|
+
'user-agent': 'whistle/' + config.name
|
|
34
|
+
};
|
|
35
|
+
httpMgr.request(addr, function(err, body, res) {
|
|
36
|
+
if (err) {
|
|
37
|
+
return util.error(err.message);
|
|
38
|
+
}
|
|
39
|
+
if (res.statusCode != 200) {
|
|
40
|
+
return util.error('Bad response (' + res.statusCode + ').');
|
|
41
|
+
}
|
|
42
|
+
if (!body || !body.length) {
|
|
43
|
+
return util.error('No content.');
|
|
44
|
+
}
|
|
45
|
+
var tempFile = path.join(commonUtil.getWhistlePath(), Date.now() + '-' + util.getHash(addr.url) + '.crt');
|
|
46
|
+
fs.writeFileSync(tempFile, body);
|
|
47
|
+
installCert(tempFile, addr.url);
|
|
48
|
+
fs.unlinkSync(tempFile);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = function(argv) {
|
|
53
|
+
var options = {};
|
|
54
|
+
argv.forEach(function(arg) {
|
|
55
|
+
if (NUM_RE.test(arg)) {
|
|
56
|
+
delete options.addr;
|
|
57
|
+
options.port = parseInt(arg, 10) || options.port;
|
|
58
|
+
} else if (net.isIP(arg)) {
|
|
59
|
+
delete options.addr;
|
|
60
|
+
options.host = arg || options.host;
|
|
61
|
+
} else if (HOST_SUFFIX_RE.test(arg)) {
|
|
62
|
+
delete options.port;
|
|
63
|
+
delete options.addr;
|
|
64
|
+
var port = RegExp.$1;
|
|
65
|
+
if (port > 0) {
|
|
66
|
+
options.port = parseInt(port, 10) || options.port;
|
|
67
|
+
}
|
|
68
|
+
var host = arg.slice(0, - port.length - 1);
|
|
69
|
+
if (host[0] === '[') {
|
|
70
|
+
host = host.substring(1);
|
|
71
|
+
}
|
|
72
|
+
var lastIndex = host.length - 1;
|
|
73
|
+
if (host[lastIndex] === ']') {
|
|
74
|
+
host = host.substring(0, lastIndex);
|
|
75
|
+
}
|
|
76
|
+
if (host && (net.isIP(host) || HOST_RE.test(host))) {
|
|
77
|
+
options.host = host || options.host;
|
|
78
|
+
}
|
|
79
|
+
} else {
|
|
80
|
+
delete options.port;
|
|
81
|
+
delete options.host;
|
|
82
|
+
if (URL_RE.test(arg)) {
|
|
83
|
+
options.addr = { url: arg };
|
|
84
|
+
} else {
|
|
85
|
+
options.addr = { file: arg };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
if (!options.addr) {
|
|
90
|
+
var host = options.host || '127.0.0.1';
|
|
91
|
+
var port = options.port || util.getDefaultPort();
|
|
92
|
+
options.addr = { url: 'http://' + host + ':' + port + '/cgi-bin/rootca' };
|
|
93
|
+
}
|
|
94
|
+
install(options.addr);
|
|
95
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function (certFile: String): void;
|
package/bin/ca/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
var spawnSync = require('child_process').spawnSync;
|
|
2
|
+
|
|
3
|
+
function checkSuccess(result) {
|
|
4
|
+
var stderr = result.stderr;
|
|
5
|
+
if (stderr && stderr.length) {
|
|
6
|
+
throw new Error(stderr + '');
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function getKeyChain() {
|
|
11
|
+
var result = spawnSync('security', ['default-keychain']);
|
|
12
|
+
checkSuccess(result);
|
|
13
|
+
return (result.stdout + '').split('"')[1];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function installMac(certPath) {
|
|
17
|
+
var result = spawnSync('security', ['add-trusted-cert', '-k', getKeyChain(), certPath]);
|
|
18
|
+
checkSuccess(result);
|
|
19
|
+
var msg = result.stdout + '';
|
|
20
|
+
if (/Error:/i.test(msg)) {
|
|
21
|
+
throw new Error(msg);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
function installWin(certFile) {
|
|
27
|
+
var result = spawnSync('certutil', ['-addstore', '-user', 'Root', certFile]);
|
|
28
|
+
checkSuccess(result);
|
|
29
|
+
if (/ERROR_CANCELLED/i.test(result.stdout + '')) {
|
|
30
|
+
throw new Error('The authorization was canceled by the user.');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = function(certFile) {
|
|
35
|
+
var platform = process.platform;
|
|
36
|
+
if (platform === 'darwin') {
|
|
37
|
+
return installMac(certFile);
|
|
38
|
+
}
|
|
39
|
+
if (platform === 'win32') {
|
|
40
|
+
return installWin(certFile);
|
|
41
|
+
}
|
|
42
|
+
throw new Error('Platform ' + platform + ' is unsupported to install root CA for now.');
|
|
43
|
+
};
|
package/bin/proxy/cli.js
CHANGED
|
@@ -2,33 +2,33 @@ var net = require('net');
|
|
|
2
2
|
var proxy = require('./index');
|
|
3
3
|
var util = require('../util');
|
|
4
4
|
|
|
5
|
-
var readConfig = util.readConfig;
|
|
6
5
|
var OFF_RE = /^(?:o|0|-{0,2}off)$/i;
|
|
7
6
|
var BYPASS_RE = /^(?:-{0,2}bypass|-x|-b)$/i;
|
|
8
7
|
var NUM_RE = /^\d+$/;
|
|
9
8
|
var HOST_SUFFIX_RE = /\:(\d+|auto)?$/;
|
|
10
9
|
var HOST_RE = /^[a-z\d_-]+(?:\.[a-z\d_-]+)*$/i;
|
|
11
10
|
|
|
12
|
-
function getDefaultPort() {
|
|
13
|
-
var conf = readConfig();
|
|
14
|
-
conf = conf && conf.options;
|
|
15
|
-
var port = conf && conf.port;
|
|
16
|
-
return port > 0 ? port : 8899;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
11
|
function enableProxy(options) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
try {
|
|
13
|
+
if (proxy.enableProxy(options)) {
|
|
14
|
+
util.info('Setting global proxy (' + options.host + ':' + options.port + ') successful.');
|
|
15
|
+
} else {
|
|
16
|
+
util.error('Failed to set global proxy (' + options.host + ':' + options.port + ').');
|
|
17
|
+
}
|
|
18
|
+
} catch (e) {
|
|
19
|
+
util.error(e.message);
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
function disableProxy() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
try {
|
|
25
|
+
if (proxy.disableProxy()) {
|
|
26
|
+
util.info('Turn off global proxy successful.');
|
|
27
|
+
} else {
|
|
28
|
+
util.error('Failed to turn off global proxy.');
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {
|
|
31
|
+
util.error(e.message);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -69,7 +69,7 @@ module.exports = function(argv) {
|
|
|
69
69
|
}
|
|
70
70
|
});
|
|
71
71
|
if (!options.port) {
|
|
72
|
-
options.port = getDefaultPort();
|
|
72
|
+
options.port = util.getDefaultPort();
|
|
73
73
|
}
|
|
74
74
|
options.host = options.host || '127.0.0.1';
|
|
75
75
|
enableProxy(options);
|
package/bin/util.js
CHANGED
|
@@ -7,12 +7,13 @@ var config = require('../lib/config');
|
|
|
7
7
|
var colors = require('colors/safe');
|
|
8
8
|
var path = require('path');
|
|
9
9
|
var createHmac = require('crypto').createHmac;
|
|
10
|
+
|
|
10
11
|
/*eslint no-console: "off"*/
|
|
11
12
|
var CHECK_RUNNING_CMD = process.platform === 'win32' ?
|
|
12
13
|
'tasklist /fi "PID eq %s" | findstr /i "node.exe"'
|
|
13
14
|
: 'ps -f -p %s | grep "node"';
|
|
14
15
|
var isWin = process.platform === 'win32';
|
|
15
|
-
|
|
16
|
+
|
|
16
17
|
function isRunning(pid, callback) {
|
|
17
18
|
pid ? cp.exec(util.format(CHECK_RUNNING_CMD, pid),
|
|
18
19
|
function (err, stdout, stderr) {
|
|
@@ -88,6 +89,15 @@ function showUsage(isRunning, options, restart) {
|
|
|
88
89
|
if (parseInt(process.version.slice(1), 10) < 6) {
|
|
89
90
|
warn(colors.bold('\nWarning: The current Node version is too low, access https://nodejs.org to install the latest version, or may not be able to Capture HTTPS CONNECTs\n'));
|
|
90
91
|
}
|
|
92
|
+
var bypass = options.init;
|
|
93
|
+
if (bypass == null) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
host: options.host || '127.0.0.1',
|
|
98
|
+
port: port,
|
|
99
|
+
bypass: typeof bypass === 'string' ? bypass : undefined
|
|
100
|
+
};
|
|
91
101
|
}
|
|
92
102
|
|
|
93
103
|
exports.showUsage = showUsage;
|
|
@@ -146,4 +156,11 @@ exports.readConfigList = readConfigList;
|
|
|
146
156
|
exports.getHash = function(str) {
|
|
147
157
|
var hmac = createHmac('sha256', 'a secret');
|
|
148
158
|
return hmac.update(str).digest('hex');
|
|
149
|
-
};
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
exports.getDefaultPort = function () {
|
|
162
|
+
var conf = readConfig();
|
|
163
|
+
conf = conf && conf.options;
|
|
164
|
+
var port = conf && conf.port;
|
|
165
|
+
return port > 0 ? port : 8899;
|
|
166
|
+
};
|
package/bin/whistle.js
CHANGED
|
@@ -8,14 +8,28 @@ var showStatus = require('./status');
|
|
|
8
8
|
var util = require('./util');
|
|
9
9
|
var plugin = require('./plugin');
|
|
10
10
|
var setProxy = require('./proxy/cli');
|
|
11
|
+
var installCA = require('./ca/cli');
|
|
11
12
|
|
|
12
|
-
var showUsage = util.showUsage;
|
|
13
13
|
var error = util.error;
|
|
14
14
|
var info = util.info;
|
|
15
15
|
|
|
16
|
+
function handleEnd(err, options, restart) {
|
|
17
|
+
options = util.showUsage(err, options, restart);
|
|
18
|
+
if (!options) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
var host = options.host + ':' + options.port;
|
|
22
|
+
var argv = [host];
|
|
23
|
+
if (options.bypass) {
|
|
24
|
+
argv.push('-x', options.bypass);
|
|
25
|
+
}
|
|
26
|
+
setProxy(argv);
|
|
27
|
+
installCA([host]);
|
|
28
|
+
}
|
|
29
|
+
|
|
16
30
|
function showStartupInfo(err, options, debugMode, restart) {
|
|
17
31
|
if (!err || err === true) {
|
|
18
|
-
return
|
|
32
|
+
return handleEnd(err, options, restart);
|
|
19
33
|
}
|
|
20
34
|
if (/listen EADDRINUSE/.test(err)) {
|
|
21
35
|
options = util.formatOptions(options);
|
|
@@ -55,7 +69,7 @@ program.setConfig({
|
|
|
55
69
|
showStartupInfo(err, options, true);
|
|
56
70
|
return;
|
|
57
71
|
}
|
|
58
|
-
|
|
72
|
+
handleEnd(false, options);
|
|
59
73
|
console.log('Press [Ctrl+C] to stop ' + config.name + '...');
|
|
60
74
|
},
|
|
61
75
|
startCallback: showStartupInfo,
|
|
@@ -85,6 +99,8 @@ program
|
|
|
85
99
|
.description('Add rules from local js file (.whistle.js by default)');
|
|
86
100
|
program.command('proxy')
|
|
87
101
|
.description('Set global proxy');
|
|
102
|
+
program.command('ca')
|
|
103
|
+
.description('Install root CA');
|
|
88
104
|
program.command('install')
|
|
89
105
|
.description('Install whistle plugin');
|
|
90
106
|
program.command('uninstall')
|
|
@@ -117,6 +133,7 @@ program
|
|
|
117
133
|
.option('-R, --reqCacheSize [reqCacheSize]', 'set the cache size of request data (600 by default)', String, undefined)
|
|
118
134
|
.option('-F, --frameCacheSize [frameCacheSize]', 'set the cache size of webSocket and socket\'s frames (512 by default)', String, undefined)
|
|
119
135
|
.option('-A, --addon [pluginPaths]', 'add custom plugin paths', String, undefined)
|
|
136
|
+
.option('--init [bypass]', 'auto set global proxy (and bypass) and install root CA')
|
|
120
137
|
.option('--config [workers]', 'start the cluster server and set worker number (os.cpus().length by default)', String, undefined)
|
|
121
138
|
.option('--cluster [config]', 'load the startup config from a local file', String, undefined)
|
|
122
139
|
.option('--dnsServer [dnsServer]', 'set custom dns servers', String, undefined)
|
|
@@ -143,6 +160,8 @@ if (cmd === 'status') {
|
|
|
143
160
|
showStatus(all, storage);
|
|
144
161
|
} else if (cmd === 'proxy') {
|
|
145
162
|
setProxy(Array.prototype.slice.call(argv, 3));
|
|
163
|
+
} else if (cmd === 'ca') {
|
|
164
|
+
installCA(Array.prototype.slice.call(argv, 3));
|
|
146
165
|
} else if (/^([a-z]{1,2})?uni(nstall)?$/.test(cmd)) {
|
|
147
166
|
plugin.uninstall(Array.prototype.slice.call(argv, 3));
|
|
148
167
|
} else if (/^([a-z]{1,2})?i(nstall)?$/.test(cmd)) {
|