node-mitmproxy-pro 1.0.0 → 1.1.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.
- package/README.md +0 -2
- package/lib/bin/index.js +34 -0
- package/lib/common/ProxyHttpAgent.js +37 -0
- package/lib/common/ProxyHttpsAgent.js +37 -0
- package/lib/common/config.js +26 -0
- package/lib/common/util.js +143 -0
- package/lib/index.js +4 -0
- package/lib/middleware/FilterMiddleware.js +1 -0
- package/lib/middleware/HtmlMiddleware.js +107 -0
- package/lib/middleware/MapLocalMiddleware.js +1 -0
- package/lib/middleware/MapRemoteMiddleware.js +1 -0
- package/lib/mitmproxy/createConnectHandler.js +40 -0
- package/lib/mitmproxy/createFakeServerCenter.js +39 -0
- package/lib/mitmproxy/createRequestHandler.js +187 -0
- package/lib/mitmproxy/createUpgradeHandler.js +59 -0
- package/lib/mitmproxy/index.js +100 -0
- package/lib/mitmproxy/middlewareHandler.js +20 -0
- package/lib/tls/CertAndKeyContainer.js +119 -0
- package/lib/tls/FakeServersCenter.js +173 -0
- package/lib/tls/tlsUtils.js +262 -0
- package/package.json +3 -2
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
|
|
4
|
+
|
|
5
|
+
var http = require('http');
|
|
6
|
+
var https = require('https');
|
|
7
|
+
var url = require('url');
|
|
8
|
+
|
|
9
|
+
var _require = require('uuid'),
|
|
10
|
+
uuidv4 = _require.v4;
|
|
11
|
+
|
|
12
|
+
var commonUtil = require('../common/util');
|
|
13
|
+
var upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i;
|
|
14
|
+
|
|
15
|
+
// create requestHandler function
|
|
16
|
+
module.exports = function createRequestHandler(requestInterceptor, responseInterceptor, middlewares, externalProxy) {
|
|
17
|
+
|
|
18
|
+
var requestId = uuidv4();
|
|
19
|
+
|
|
20
|
+
// return
|
|
21
|
+
return function requestHandler(req, res, ssl) {
|
|
22
|
+
var _this = this;
|
|
23
|
+
|
|
24
|
+
var proxyReq;
|
|
25
|
+
|
|
26
|
+
var rOptions = commonUtil.getOptionsFormRequest(req, ssl, externalProxy);
|
|
27
|
+
|
|
28
|
+
if (rOptions.headers.connection === 'close') {
|
|
29
|
+
req.socket.setKeepAlive(false);
|
|
30
|
+
} else if (rOptions.customSocketId != null) {
|
|
31
|
+
// for NTLM
|
|
32
|
+
req.socket.setKeepAlive(true, 60 * 60 * 1000);
|
|
33
|
+
} else {
|
|
34
|
+
req.socket.setKeepAlive(true, 30000);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var requestInterceptorPromise = function requestInterceptorPromise() {
|
|
38
|
+
return new Promise(function (resolve, reject) {
|
|
39
|
+
var next = function next() {
|
|
40
|
+
resolve();
|
|
41
|
+
};
|
|
42
|
+
try {
|
|
43
|
+
if (typeof requestInterceptor === 'function') {
|
|
44
|
+
requestInterceptor.call(null, requestId, rOptions, req, res, proxyReq, ssl, next);
|
|
45
|
+
} else {
|
|
46
|
+
resolve();
|
|
47
|
+
}
|
|
48
|
+
} catch (e) {
|
|
49
|
+
reject(e);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
var proxyRequestPromise = function proxyRequestPromise() {
|
|
55
|
+
return new Promise(function (resolve, reject) {
|
|
56
|
+
|
|
57
|
+
rOptions.host = rOptions.hostname || rOptions.host || 'localhost';
|
|
58
|
+
|
|
59
|
+
// use the binded socket for NTLM
|
|
60
|
+
if (rOptions.agent && rOptions.customSocketId != null && rOptions.agent.getName) {
|
|
61
|
+
var socketName = rOptions.agent.getName(rOptions);
|
|
62
|
+
var bindingSocket = rOptions.agent.sockets[socketName];
|
|
63
|
+
if (bindingSocket && bindingSocket.length > 0) {
|
|
64
|
+
bindingSocket[0].once('free', onFree);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
onFree();
|
|
69
|
+
function onFree() {
|
|
70
|
+
proxyReq = (rOptions.protocol == 'https:' ? https : http).request(rOptions, function (proxyRes) {
|
|
71
|
+
resolve(proxyRes);
|
|
72
|
+
});
|
|
73
|
+
proxyReq.on('timeout', function () {
|
|
74
|
+
reject(rOptions.host + ':' + rOptions.port + ', request timeout');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
proxyReq.on('error', function (e) {
|
|
78
|
+
reject(e);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
proxyReq.on('aborted', function () {
|
|
82
|
+
reject('server aborted reqest');
|
|
83
|
+
req.abort();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
req.on('aborted', function () {
|
|
87
|
+
proxyReq.abort();
|
|
88
|
+
});
|
|
89
|
+
requestInterceptorPromise();
|
|
90
|
+
// req.pipe(proxyReq);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// workflow control
|
|
96
|
+
_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
|
|
97
|
+
var proxyRes, responseInterceptorPromise;
|
|
98
|
+
return regeneratorRuntime.wrap(function _callee$(_context) {
|
|
99
|
+
while (1) {
|
|
100
|
+
switch (_context.prev = _context.next) {
|
|
101
|
+
case 0:
|
|
102
|
+
_context.next = 2;
|
|
103
|
+
return proxyRequestPromise();
|
|
104
|
+
|
|
105
|
+
case 2:
|
|
106
|
+
proxyRes = _context.sent;
|
|
107
|
+
|
|
108
|
+
if (!res.finished) {
|
|
109
|
+
_context.next = 5;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return _context.abrupt('return', false);
|
|
114
|
+
|
|
115
|
+
case 5:
|
|
116
|
+
responseInterceptorPromise = new Promise(function (resolve, reject) {
|
|
117
|
+
var next = function next() {
|
|
118
|
+
resolve();
|
|
119
|
+
};
|
|
120
|
+
try {
|
|
121
|
+
if (typeof responseInterceptor === 'function') {
|
|
122
|
+
responseInterceptor.call(null, requestId, res, proxyRes, ssl, next);
|
|
123
|
+
} else {
|
|
124
|
+
resolve();
|
|
125
|
+
}
|
|
126
|
+
} catch (e) {
|
|
127
|
+
reject(e);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
_context.next = 8;
|
|
131
|
+
return responseInterceptorPromise;
|
|
132
|
+
|
|
133
|
+
case 8:
|
|
134
|
+
if (!res.finished) {
|
|
135
|
+
_context.next = 10;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return _context.abrupt('return', false);
|
|
140
|
+
|
|
141
|
+
case 10:
|
|
142
|
+
_context.prev = 10;
|
|
143
|
+
|
|
144
|
+
if (!res.headersSent) {
|
|
145
|
+
// prevent duplicate set headers
|
|
146
|
+
Object.keys(proxyRes.headers).forEach(function (key) {
|
|
147
|
+
if (proxyRes.headers[key] != undefined) {
|
|
148
|
+
// https://github.com/nodejitsu/node-http-proxy/issues/362
|
|
149
|
+
if (/^www-authenticate$/i.test(key)) {
|
|
150
|
+
if (proxyRes.headers[key]) {
|
|
151
|
+
proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
|
|
152
|
+
}
|
|
153
|
+
key = 'www-authenticate';
|
|
154
|
+
}
|
|
155
|
+
res.setHeader(key, proxyRes.headers[key]);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
res.writeHead(proxyRes.statusCode);
|
|
160
|
+
proxyRes.pipe(res);
|
|
161
|
+
}
|
|
162
|
+
_context.next = 17;
|
|
163
|
+
break;
|
|
164
|
+
|
|
165
|
+
case 14:
|
|
166
|
+
_context.prev = 14;
|
|
167
|
+
_context.t0 = _context['catch'](10);
|
|
168
|
+
throw _context.t0;
|
|
169
|
+
|
|
170
|
+
case 17:
|
|
171
|
+
case 'end':
|
|
172
|
+
return _context.stop();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}, _callee, _this, [[10, 14]]);
|
|
176
|
+
}))().then(function (flag) {
|
|
177
|
+
// do nothing
|
|
178
|
+
}, function (e) {
|
|
179
|
+
if (!res.finished) {
|
|
180
|
+
res.writeHead(500);
|
|
181
|
+
res.write('Node-MitmProxy Warning:\n\n ' + e.toString());
|
|
182
|
+
res.end();
|
|
183
|
+
}
|
|
184
|
+
console.error(e);
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var http = require('http');
|
|
4
|
+
var https = require('https');
|
|
5
|
+
var url = require('url');
|
|
6
|
+
var util = require('../common/util');
|
|
7
|
+
|
|
8
|
+
// copy from node-http-proxy. ^_^
|
|
9
|
+
|
|
10
|
+
// create connectHandler function
|
|
11
|
+
module.exports = function createUpgradeHandler() {
|
|
12
|
+
|
|
13
|
+
// return
|
|
14
|
+
return function upgradeHandler(req, cltSocket, head, ssl) {
|
|
15
|
+
var clientOptions = util.getOptionsFormRequest(req, ssl);
|
|
16
|
+
var proxyReq = (ssl ? https : http).request(clientOptions);
|
|
17
|
+
proxyReq.on('error', function (e) {
|
|
18
|
+
console.error(e);
|
|
19
|
+
});
|
|
20
|
+
proxyReq.on('response', function (res) {
|
|
21
|
+
// if upgrade event isn't going to happen, close the socket
|
|
22
|
+
if (!res.upgrade) cltSocket.end();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
proxyReq.on('upgrade', function (proxyRes, proxySocket, proxyHead) {
|
|
26
|
+
proxySocket.on('error', function (e) {
|
|
27
|
+
console.error(e);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
cltSocket.on('error', function () {
|
|
31
|
+
proxySocket.end();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
proxySocket.setTimeout(0);
|
|
35
|
+
proxySocket.setNoDelay(true);
|
|
36
|
+
|
|
37
|
+
proxySocket.setKeepAlive(true, 0);
|
|
38
|
+
|
|
39
|
+
if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead);
|
|
40
|
+
|
|
41
|
+
cltSocket.write(Object.keys(proxyRes.headers).reduce(function (head, key) {
|
|
42
|
+
var value = proxyRes.headers[key];
|
|
43
|
+
|
|
44
|
+
if (!Array.isArray(value)) {
|
|
45
|
+
head.push(key + ': ' + value);
|
|
46
|
+
return head;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (var i = 0; i < value.length; i++) {
|
|
50
|
+
head.push(key + ': ' + value[i]);
|
|
51
|
+
}
|
|
52
|
+
return head;
|
|
53
|
+
}, ['HTTP/1.1 101 Switching Protocols']).join('\r\n') + '\r\n\r\n');
|
|
54
|
+
|
|
55
|
+
proxySocket.pipe(cltSocket).pipe(proxySocket);
|
|
56
|
+
});
|
|
57
|
+
proxyReq.end();
|
|
58
|
+
};
|
|
59
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tlsUtils = require('../tls/tlsUtils');
|
|
4
|
+
var http = require('http');
|
|
5
|
+
var config = require('../common/config');
|
|
6
|
+
var colors = require('colors');
|
|
7
|
+
var createRequestHandler = require('./createRequestHandler');
|
|
8
|
+
var createConnectHandler = require('./createConnectHandler');
|
|
9
|
+
var createFakeServerCenter = require('./createFakeServerCenter');
|
|
10
|
+
var createUpgradeHandler = require('./createUpgradeHandler');
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
/**
|
|
14
|
+
* 启动中间人代理服务器
|
|
15
|
+
* @param {Object} options 配置
|
|
16
|
+
* @param {Number} options.port 代理端口
|
|
17
|
+
* @param {String} options.caCertPath CA证书路径
|
|
18
|
+
* @param {String} options.caKeyPath CA私钥路径
|
|
19
|
+
* @param {Function} options.sslConnectInterceptor SSL连接拦截器
|
|
20
|
+
* @param {Function} options.requestInterceptor 请求拦截器
|
|
21
|
+
* @param {Function} options.responseInterceptor 响应拦截器
|
|
22
|
+
* @param {Number} options.getCertSocketTimeout 获取证书超时时间
|
|
23
|
+
* @param {Array} options.middlewares 中间件
|
|
24
|
+
* @param {Object} options.externalProxy 外部代理
|
|
25
|
+
* @returns {http.Server} http代理服务器(关闭请使用.close()方法)
|
|
26
|
+
*/
|
|
27
|
+
createProxy: function createProxy(_ref) {
|
|
28
|
+
var _ref$port = _ref.port,
|
|
29
|
+
port = _ref$port === undefined ? config.defaultPort : _ref$port,
|
|
30
|
+
caCertPath = _ref.caCertPath,
|
|
31
|
+
caKeyPath = _ref.caKeyPath,
|
|
32
|
+
sslConnectInterceptor = _ref.sslConnectInterceptor,
|
|
33
|
+
requestInterceptor = _ref.requestInterceptor,
|
|
34
|
+
responseInterceptor = _ref.responseInterceptor,
|
|
35
|
+
_ref$getCertSocketTim = _ref.getCertSocketTimeout,
|
|
36
|
+
getCertSocketTimeout = _ref$getCertSocketTim === undefined ? 1 * 1000 : _ref$getCertSocketTim,
|
|
37
|
+
_ref$middlewares = _ref.middlewares,
|
|
38
|
+
middlewares = _ref$middlewares === undefined ? [] : _ref$middlewares,
|
|
39
|
+
externalProxy = _ref.externalProxy;
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
// Don't reject unauthorized
|
|
43
|
+
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
|
|
44
|
+
|
|
45
|
+
if (!caCertPath && !caKeyPath) {
|
|
46
|
+
var rs = this.createCA();
|
|
47
|
+
caCertPath = rs.caCertPath;
|
|
48
|
+
caKeyPath = rs.caKeyPath;
|
|
49
|
+
if (rs.create) {
|
|
50
|
+
console.log(colors.cyan('CA Cert saved in: ' + caCertPath));
|
|
51
|
+
console.log(colors.cyan('CA private key saved in: ' + caKeyPath));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
port = ~~port;
|
|
56
|
+
var requestHandler = createRequestHandler(requestInterceptor, responseInterceptor, middlewares, externalProxy);
|
|
57
|
+
|
|
58
|
+
var upgradeHandler = createUpgradeHandler();
|
|
59
|
+
|
|
60
|
+
var fakeServersCenter = createFakeServerCenter({
|
|
61
|
+
caCertPath: caCertPath,
|
|
62
|
+
caKeyPath: caKeyPath,
|
|
63
|
+
requestHandler: requestHandler,
|
|
64
|
+
upgradeHandler: upgradeHandler,
|
|
65
|
+
getCertSocketTimeout: getCertSocketTimeout
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
var connectHandler = createConnectHandler(sslConnectInterceptor, fakeServersCenter);
|
|
69
|
+
|
|
70
|
+
var server = new http.Server();
|
|
71
|
+
server.listen(port, function () {
|
|
72
|
+
console.log(colors.green('node-mitmproxy\u542F\u52A8\u7AEF\u53E3: ' + port));
|
|
73
|
+
server.on('error', function (e) {
|
|
74
|
+
console.error(colors.red(e));
|
|
75
|
+
});
|
|
76
|
+
server.on('request', function (req, res) {
|
|
77
|
+
var ssl = false;
|
|
78
|
+
requestHandler(req, res, ssl);
|
|
79
|
+
});
|
|
80
|
+
// tunneling for https
|
|
81
|
+
server.on('connect', function (req, cltSocket, head) {
|
|
82
|
+
connectHandler(req, cltSocket, head);
|
|
83
|
+
});
|
|
84
|
+
// TODO: handler WebSocket
|
|
85
|
+
server.on('upgrade', function (req, socket, head) {
|
|
86
|
+
var ssl = false;
|
|
87
|
+
upgradeHandler(req, socket, head, ssl);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return server;
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
// 创建CA证书
|
|
95
|
+
createCA: function createCA() {
|
|
96
|
+
var caBasePath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : config.getDefaultCABasePath();
|
|
97
|
+
|
|
98
|
+
return tlsUtils.initCA(caBasePath);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _ = require('lodash');
|
|
4
|
+
module.exports = function (middlewares) {
|
|
5
|
+
if (middlewares) {
|
|
6
|
+
if (Object.prototype.toString.call(middlewares) !== '[object Array]') {
|
|
7
|
+
throw new TypeError('middlewares must be a array');
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
var sslConnectInterceptors = [];
|
|
12
|
+
var requestInterceptors = [];
|
|
13
|
+
var responseInterceptors = [];
|
|
14
|
+
|
|
15
|
+
_.each(middlewares, function (m) {
|
|
16
|
+
if (m.buildIn === false || m.buildIn === 'false') {} else {
|
|
17
|
+
m.name;
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
4
|
+
|
|
5
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
6
|
+
|
|
7
|
+
var tlsUtils = require('./tlsUtils');
|
|
8
|
+
var https = require('https');
|
|
9
|
+
|
|
10
|
+
module.exports = function () {
|
|
11
|
+
function CertAndKeyContainer(_ref) {
|
|
12
|
+
var _ref$maxLength = _ref.maxLength,
|
|
13
|
+
maxLength = _ref$maxLength === undefined ? 1000 : _ref$maxLength,
|
|
14
|
+
_ref$getCertSocketTim = _ref.getCertSocketTimeout,
|
|
15
|
+
getCertSocketTimeout = _ref$getCertSocketTim === undefined ? 2 * 1000 : _ref$getCertSocketTim,
|
|
16
|
+
caCert = _ref.caCert,
|
|
17
|
+
caKey = _ref.caKey;
|
|
18
|
+
|
|
19
|
+
_classCallCheck(this, CertAndKeyContainer);
|
|
20
|
+
|
|
21
|
+
this.queue = [];
|
|
22
|
+
this.maxLength = maxLength;
|
|
23
|
+
this.getCertSocketTimeout = getCertSocketTimeout;
|
|
24
|
+
this.caCert = caCert;
|
|
25
|
+
this.caKey = caKey;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_createClass(CertAndKeyContainer, [{
|
|
29
|
+
key: 'addCertPromise',
|
|
30
|
+
value: function addCertPromise(certPromiseObj) {
|
|
31
|
+
if (this.queue.length >= this.maxLength) {
|
|
32
|
+
this.queue.shift();
|
|
33
|
+
}
|
|
34
|
+
this.queue.push(certPromiseObj);
|
|
35
|
+
return certPromiseObj;
|
|
36
|
+
}
|
|
37
|
+
}, {
|
|
38
|
+
key: 'getCertPromise',
|
|
39
|
+
value: function getCertPromise(hostname, port) {
|
|
40
|
+
var _this = this;
|
|
41
|
+
|
|
42
|
+
for (var i = 0; i < this.queue.length; i++) {
|
|
43
|
+
var _certPromiseObj = this.queue[i];
|
|
44
|
+
var mappingHostNames = _certPromiseObj.mappingHostNames;
|
|
45
|
+
for (var j = 0; j < mappingHostNames.length; j++) {
|
|
46
|
+
var DNSName = mappingHostNames[j];
|
|
47
|
+
if (tlsUtils.isMappingHostName(DNSName, hostname)) {
|
|
48
|
+
this.reRankCert(i);
|
|
49
|
+
return _certPromiseObj.promise;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
var certPromiseObj = {
|
|
55
|
+
mappingHostNames: [hostname] // temporary hostname
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
var promise = new Promise(function (resolve, reject) {
|
|
59
|
+
var once = true;
|
|
60
|
+
var _resolve = function _resolve(_certObj) {
|
|
61
|
+
if (once) {
|
|
62
|
+
once = false;
|
|
63
|
+
var mappingHostNames = tlsUtils.getMappingHostNamesFormCert(_certObj.cert);
|
|
64
|
+
certPromiseObj.mappingHostNames = mappingHostNames; // change
|
|
65
|
+
resolve(_certObj);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
var certObj = void 0;
|
|
69
|
+
var preReq = https.request({
|
|
70
|
+
port: port,
|
|
71
|
+
hostname: hostname,
|
|
72
|
+
path: '/',
|
|
73
|
+
method: 'HEAD'
|
|
74
|
+
}, function (preRes) {
|
|
75
|
+
try {
|
|
76
|
+
var realCert = preRes.socket.getPeerCertificate();
|
|
77
|
+
if (realCert) {
|
|
78
|
+
try {
|
|
79
|
+
certObj = tlsUtils.createFakeCertificateByCA(_this.caKey, _this.caCert, realCert);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
certObj = tlsUtils.createFakeCertificateByDomain(_this.caKey, _this.caCert, hostname);
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
certObj = tlsUtils.createFakeCertificateByDomain(_this.caKey, _this.caCert, hostname);
|
|
85
|
+
}
|
|
86
|
+
_resolve(certObj);
|
|
87
|
+
} catch (e) {
|
|
88
|
+
reject(e);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
preReq.setTimeout(~~_this.getCertSocketTimeout, function () {
|
|
92
|
+
if (!certObj) {
|
|
93
|
+
certObj = tlsUtils.createFakeCertificateByDomain(_this.caKey, _this.caCert, hostname);
|
|
94
|
+
_resolve(certObj);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
preReq.on('error', function (e) {
|
|
98
|
+
if (!certObj) {
|
|
99
|
+
certObj = tlsUtils.createFakeCertificateByDomain(_this.caKey, _this.caCert, hostname);
|
|
100
|
+
_resolve(certObj);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
preReq.end();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
certPromiseObj.promise = promise;
|
|
107
|
+
|
|
108
|
+
return this.addCertPromise(certPromiseObj).promise;
|
|
109
|
+
}
|
|
110
|
+
}, {
|
|
111
|
+
key: 'reRankCert',
|
|
112
|
+
value: function reRankCert(index) {
|
|
113
|
+
// index ==> queue foot
|
|
114
|
+
this.queue.push(this.queue.splice(index, 1)[0]);
|
|
115
|
+
}
|
|
116
|
+
}]);
|
|
117
|
+
|
|
118
|
+
return CertAndKeyContainer;
|
|
119
|
+
}();
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
|
4
|
+
|
|
5
|
+
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
|
|
6
|
+
|
|
7
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
8
|
+
|
|
9
|
+
var https = require('https');
|
|
10
|
+
var tlsUtils = require('./tlsUtils');
|
|
11
|
+
var CertAndKeyContainer = require('./CertAndKeyContainer');
|
|
12
|
+
var forge = require('node-forge');
|
|
13
|
+
var pki = forge.pki;
|
|
14
|
+
var colors = require('colors');
|
|
15
|
+
var tls = require('tls');
|
|
16
|
+
|
|
17
|
+
module.exports = function () {
|
|
18
|
+
function FakeServersCenter(_ref) {
|
|
19
|
+
var _ref$maxLength = _ref.maxLength,
|
|
20
|
+
maxLength = _ref$maxLength === undefined ? 100 : _ref$maxLength,
|
|
21
|
+
requestHandler = _ref.requestHandler,
|
|
22
|
+
upgradeHandler = _ref.upgradeHandler,
|
|
23
|
+
caCert = _ref.caCert,
|
|
24
|
+
caKey = _ref.caKey,
|
|
25
|
+
getCertSocketTimeout = _ref.getCertSocketTimeout;
|
|
26
|
+
|
|
27
|
+
_classCallCheck(this, FakeServersCenter);
|
|
28
|
+
|
|
29
|
+
this.queue = [];
|
|
30
|
+
this.maxLength = maxLength;
|
|
31
|
+
this.requestHandler = requestHandler;
|
|
32
|
+
this.upgradeHandler = upgradeHandler;
|
|
33
|
+
this.certAndKeyContainer = new CertAndKeyContainer({
|
|
34
|
+
getCertSocketTimeout: getCertSocketTimeout,
|
|
35
|
+
caCert: caCert,
|
|
36
|
+
caKey: caKey
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_createClass(FakeServersCenter, [{
|
|
41
|
+
key: 'addServerPromise',
|
|
42
|
+
value: function addServerPromise(serverPromiseObj) {
|
|
43
|
+
if (this.queue.length >= this.maxLength) {
|
|
44
|
+
var delServerObj = this.queue.shift();
|
|
45
|
+
try {
|
|
46
|
+
delServerObj.serverObj.server.close();
|
|
47
|
+
} catch (e) {
|
|
48
|
+
console.log(e);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
this.queue.push(serverPromiseObj);
|
|
52
|
+
return serverPromiseObj;
|
|
53
|
+
}
|
|
54
|
+
}, {
|
|
55
|
+
key: 'getServerPromise',
|
|
56
|
+
value: function getServerPromise(hostname, port) {
|
|
57
|
+
var _this = this;
|
|
58
|
+
|
|
59
|
+
for (var i = 0; i < this.queue.length; i++) {
|
|
60
|
+
var _serverPromiseObj = this.queue[i];
|
|
61
|
+
var mappingHostNames = _serverPromiseObj.mappingHostNames;
|
|
62
|
+
for (var j = 0; j < mappingHostNames.length; j++) {
|
|
63
|
+
var DNSName = mappingHostNames[j];
|
|
64
|
+
if (tlsUtils.isMappingHostName(DNSName, hostname)) {
|
|
65
|
+
this.reRankServer(i);
|
|
66
|
+
return _serverPromiseObj.promise;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
var serverPromiseObj = {
|
|
72
|
+
mappingHostNames: [hostname] // temporary hostname
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
var promise = new Promise(function (resolve, reject) {
|
|
76
|
+
|
|
77
|
+
_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {
|
|
78
|
+
var certObj, cert, key, certPem, keyPem, fakeServer, serverObj;
|
|
79
|
+
return regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
80
|
+
while (1) {
|
|
81
|
+
switch (_context2.prev = _context2.next) {
|
|
82
|
+
case 0:
|
|
83
|
+
_context2.next = 2;
|
|
84
|
+
return _this.certAndKeyContainer.getCertPromise(hostname, port);
|
|
85
|
+
|
|
86
|
+
case 2:
|
|
87
|
+
certObj = _context2.sent;
|
|
88
|
+
cert = certObj.cert;
|
|
89
|
+
key = certObj.key;
|
|
90
|
+
certPem = pki.certificateToPem(cert);
|
|
91
|
+
keyPem = pki.privateKeyToPem(key);
|
|
92
|
+
fakeServer = new https.Server({
|
|
93
|
+
key: keyPem,
|
|
94
|
+
cert: certPem,
|
|
95
|
+
SNICallback: function SNICallback(hostname, done) {
|
|
96
|
+
_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
|
|
97
|
+
var certObj;
|
|
98
|
+
return regeneratorRuntime.wrap(function _callee$(_context) {
|
|
99
|
+
while (1) {
|
|
100
|
+
switch (_context.prev = _context.next) {
|
|
101
|
+
case 0:
|
|
102
|
+
_context.next = 2;
|
|
103
|
+
return _this.certAndKeyContainer.getCertPromise(hostname, port);
|
|
104
|
+
|
|
105
|
+
case 2:
|
|
106
|
+
certObj = _context.sent;
|
|
107
|
+
|
|
108
|
+
done(null, tls.createSecureContext({
|
|
109
|
+
key: pki.privateKeyToPem(certObj.key),
|
|
110
|
+
cert: pki.certificateToPem(certObj.cert)
|
|
111
|
+
}));
|
|
112
|
+
|
|
113
|
+
case 4:
|
|
114
|
+
case 'end':
|
|
115
|
+
return _context.stop();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}, _callee, _this);
|
|
119
|
+
}))();
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
serverObj = {
|
|
123
|
+
cert: cert,
|
|
124
|
+
key: key,
|
|
125
|
+
server: fakeServer,
|
|
126
|
+
port: 0 // if prot === 0 ,should listen server's `listening` event.
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
serverPromiseObj.serverObj = serverObj;
|
|
130
|
+
fakeServer.listen(0, function () {
|
|
131
|
+
var address = fakeServer.address();
|
|
132
|
+
serverObj.port = address.port;
|
|
133
|
+
});
|
|
134
|
+
fakeServer.on('request', function (req, res) {
|
|
135
|
+
var ssl = true;
|
|
136
|
+
_this.requestHandler(req, res, ssl);
|
|
137
|
+
});
|
|
138
|
+
fakeServer.on('error', function (e) {
|
|
139
|
+
console.error(e);
|
|
140
|
+
});
|
|
141
|
+
fakeServer.on('listening', function () {
|
|
142
|
+
var mappingHostNames = tlsUtils.getMappingHostNamesFormCert(certObj.cert);
|
|
143
|
+
serverPromiseObj.mappingHostNames = mappingHostNames;
|
|
144
|
+
resolve(serverObj);
|
|
145
|
+
});
|
|
146
|
+
fakeServer.on('upgrade', function (req, socket, head) {
|
|
147
|
+
var ssl = true;
|
|
148
|
+
_this.upgradeHandler(req, socket, head, ssl);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
case 15:
|
|
152
|
+
case 'end':
|
|
153
|
+
return _context2.stop();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}, _callee2, _this);
|
|
157
|
+
}))();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
serverPromiseObj.promise = promise;
|
|
161
|
+
|
|
162
|
+
return this.addServerPromise(serverPromiseObj).promise;
|
|
163
|
+
}
|
|
164
|
+
}, {
|
|
165
|
+
key: 'reRankServer',
|
|
166
|
+
value: function reRankServer(index) {
|
|
167
|
+
// index ==> queue foot
|
|
168
|
+
this.queue.push(this.queue.splice(index, 1)[0]);
|
|
169
|
+
}
|
|
170
|
+
}]);
|
|
171
|
+
|
|
172
|
+
return FakeServersCenter;
|
|
173
|
+
}();
|