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 CHANGED
@@ -44,7 +44,6 @@ module.exports = {
44
44
  效果图:
45
45
  <img width=500 src="./doc/img/hello_node-mitmproxy.jpg" />
46
46
 
47
- [详细配置说明](https://github.com/CyrilGuoCODE/node-mitmproxy-pro#4配置详细说明)
48
47
  [更多例子](./example/config/)
49
48
  #### 启动方式
50
49
  ```
@@ -61,7 +60,6 @@ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keyc
61
60
  ```
62
61
  ###### windows
63
62
  注: 证书需要安装到 ** 受信任的根证书目录 ** 下
64
- 参考 [issues#3](https://github.com/CyrilGuoCODE/node-mitmproxy-pro/issues/3)
65
63
  ```
66
64
  start %HOMEPATH%/node-mitmproxy-pro/node-mitmproxy-pro.ca.crt
67
65
  ```
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
5
+
6
+ require('babel-polyfill');
7
+ var mitmproxy = require('../mitmproxy/index');
8
+ var program = require('commander');
9
+ var packageJson = require('../../package.json');
10
+ var tlsUtils = require('../tls/tlsUtils');
11
+ var fs = require('fs');
12
+ var path = require('path');
13
+ var colors = require('colors');
14
+
15
+ fs.existsSync = fs.existsSync || path.existsSync;
16
+
17
+ program.version(packageJson.version).option('-c, --config [value]', 'config file path').parse(process.argv);
18
+
19
+ console.log(program.config);
20
+
21
+ var configPath = path.resolve(program.config);
22
+
23
+ if (fs.existsSync(configPath)) {
24
+
25
+ var configObject = require(configPath);
26
+
27
+ if ((typeof configObject === 'undefined' ? 'undefined' : _typeof(configObject)) !== 'object') {
28
+ console.error(colors.red('Config Error in ' + configPath));
29
+ } else {
30
+ mitmproxy.createProxy(configObject);
31
+ }
32
+ } else {
33
+ console.error(colors.red('Can not find `config file` file: ' + configPath));
34
+ }
@@ -0,0 +1,37 @@
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
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
8
+
9
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
10
+
11
+ var AgentOrigin = require('agentkeepalive');
12
+
13
+ module.exports = function (_AgentOrigin) {
14
+ _inherits(Agent, _AgentOrigin);
15
+
16
+ function Agent() {
17
+ _classCallCheck(this, Agent);
18
+
19
+ return _possibleConstructorReturn(this, (Agent.__proto__ || Object.getPrototypeOf(Agent)).apply(this, arguments));
20
+ }
21
+
22
+ _createClass(Agent, [{
23
+ key: 'getName',
24
+
25
+ // Hacky
26
+ value: function getName(option) {
27
+ var name = AgentOrigin.prototype.getName.call(this, option);
28
+ name += ':';
29
+ if (option.customSocketId) {
30
+ name += option.customSocketId;
31
+ }
32
+ return name;
33
+ }
34
+ }]);
35
+
36
+ return Agent;
37
+ }(AgentOrigin);
@@ -0,0 +1,37 @@
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
+ function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
8
+
9
+ function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
10
+
11
+ var HttpsAgentOrigin = require('agentkeepalive').HttpsAgent;
12
+
13
+ module.exports = function (_HttpsAgentOrigin) {
14
+ _inherits(HttpsAgent, _HttpsAgentOrigin);
15
+
16
+ function HttpsAgent() {
17
+ _classCallCheck(this, HttpsAgent);
18
+
19
+ return _possibleConstructorReturn(this, (HttpsAgent.__proto__ || Object.getPrototypeOf(HttpsAgent)).apply(this, arguments));
20
+ }
21
+
22
+ _createClass(HttpsAgent, [{
23
+ key: 'getName',
24
+
25
+ // Hacky
26
+ value: function getName(option) {
27
+ var name = HttpsAgentOrigin.prototype.getName.call(this, option);
28
+ name += ':';
29
+ if (option.customSocketId) {
30
+ name += option.customSocketId;
31
+ }
32
+ return name;
33
+ }
34
+ }]);
35
+
36
+ return HttpsAgent;
37
+ }(HttpsAgentOrigin);
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ var path = require('path');
4
+
5
+ var config = exports;
6
+
7
+ config.caCertFileName = 'node-mitmproxy.ca.crt';
8
+
9
+ config.caKeyFileName = 'node-mitmproxy.ca.key.pem';
10
+
11
+ config.defaultPort = 6789;
12
+
13
+ config.caName = 'node-mitmproxy CA';
14
+
15
+ config.getDefaultCABasePath = function () {
16
+ var userHome = process.env.HOME || process.env.USERPROFILE;
17
+ return path.resolve(userHome, './node-mitmproxy');
18
+ };
19
+
20
+ config.getDefaultCACertPath = function () {
21
+ return path.resolve(config.getDefaultCABasePath(), config.caCertFileName);
22
+ };
23
+
24
+ config.getDefaultCACertPath = function () {
25
+ return path.resolve(config.getDefaultCABasePath(), config.caKeyFileName);
26
+ };
@@ -0,0 +1,143 @@
1
+ 'use strict';
2
+
3
+ var url = require('url');
4
+ var Agent = require('./ProxyHttpAgent');
5
+ var HttpsAgent = require('./ProxyHttpsAgent');
6
+ var tunnelAgent = require('tunnel-agent');
7
+
8
+ var util = exports;
9
+ var httpsAgent = new HttpsAgent({
10
+ keepAlive: true,
11
+ timeout: 60000,
12
+ keepAliveTimeout: 30000, // free socket keepalive for 30 seconds
13
+ rejectUnauthorized: false
14
+ });
15
+ var httpAgent = new Agent({
16
+ keepAlive: true,
17
+ timeout: 60000,
18
+ keepAliveTimeout: 30000 // free socket keepalive for 30 seconds
19
+ });
20
+ var socketId = 0;
21
+
22
+ var httpOverHttpAgent, httpsOverHttpAgent, httpOverHttpsAgent, httpsOverHttpsAgent;
23
+
24
+ util.getOptionsFormRequest = function (req, ssl) {
25
+ var externalProxy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
26
+
27
+ var urlObject = url.parse(req.url);
28
+ var defaultPort = ssl ? 443 : 80;
29
+ var protocol = ssl ? 'https:' : 'http:';
30
+ var headers = Object.assign({}, req.headers);
31
+ var externalProxyUrl = null;
32
+
33
+ if (externalProxy) {
34
+ if (typeof externalProxy === 'string') {
35
+ externalProxyUrl = externalProxy;
36
+ } else if (typeof externalProxy === 'function') {
37
+ try {
38
+ externalProxyUrl = externalProxy(req, ssl);
39
+ } catch (e) {
40
+ console.error(e);
41
+ }
42
+ }
43
+ }
44
+
45
+ delete headers['proxy-connection'];
46
+ var agent = false;
47
+ if (!externalProxyUrl) {
48
+ // keepAlive
49
+ if (headers.connection !== 'close') {
50
+ if (protocol == 'https:') {
51
+ agent = httpsAgent;
52
+ } else {
53
+ agent = httpAgent;
54
+ }
55
+ headers.connection = 'keep-alive';
56
+ }
57
+ } else {
58
+ agent = util.getTunnelAgent(protocol === 'https:', externalProxyUrl);
59
+ }
60
+
61
+ var options = {
62
+ protocol: protocol,
63
+ hostname: req.headers.host.split(':')[0],
64
+ method: req.method,
65
+ port: req.headers.host.split(':')[1] || defaultPort,
66
+ path: urlObject.path,
67
+ headers: req.headers,
68
+ agent: agent
69
+ };
70
+
71
+ if (protocol === 'http:' && externalProxyUrl && url.parse(externalProxyUrl).protocol === 'http:') {
72
+ var externalURL = url.parse(externalProxyUrl);
73
+ options.hostname = externalURL.hostname;
74
+ options.port = externalURL.port;
75
+ // support non-transparent proxy
76
+ options.path = 'http://' + urlObject.host + urlObject.path;
77
+ }
78
+
79
+ // mark a socketId for Agent to bind socket for NTLM
80
+ if (req.socket.customSocketId) {
81
+ options.customSocketId = req.socket.customSocketId;
82
+ } else if (headers['authorization']) {
83
+ options.customSocketId = req.socket.customSocketId = socketId++;
84
+ }
85
+
86
+ return options;
87
+ };
88
+
89
+ util.getTunnelAgent = function (requestIsSSL, externalProxyUrl) {
90
+ var urlObject = url.parse(externalProxyUrl);
91
+ var protocol = urlObject.protocol || 'http:';
92
+ var port = urlObject.port;
93
+ if (!port) {
94
+ port = protocol === 'http:' ? 80 : 443;
95
+ }
96
+ var hostname = urlObject.hostname || 'localhost';
97
+
98
+ if (requestIsSSL) {
99
+ if (protocol === 'http:') {
100
+ if (!httpsOverHttpAgent) {
101
+ httpsOverHttpAgent = tunnelAgent.httpsOverHttp({
102
+ proxy: {
103
+ host: hostname,
104
+ port: port
105
+ }
106
+ });
107
+ }
108
+ return httpsOverHttpAgent;
109
+ } else {
110
+ if (!httpsOverHttpsAgent) {
111
+ httpsOverHttpsAgent = tunnelAgent.httpsOverHttps({
112
+ proxy: {
113
+ host: hostname,
114
+ port: port
115
+ }
116
+ });
117
+ }
118
+ return httpsOverHttpsAgent;
119
+ }
120
+ } else {
121
+ if (protocol === 'http:') {
122
+ // if (!httpOverHttpAgent) {
123
+ // httpOverHttpAgent = tunnelAgent.httpOverHttp({
124
+ // proxy: {
125
+ // host: hostname,
126
+ // port: port
127
+ // }
128
+ // });
129
+ // }
130
+ return false;
131
+ } else {
132
+ if (!httpOverHttpsAgent) {
133
+ httpOverHttpsAgent = tunnelAgent.httpOverHttps({
134
+ proxy: {
135
+ host: hostname,
136
+ port: port
137
+ }
138
+ });
139
+ }
140
+ return httpOverHttpsAgent;
141
+ }
142
+ }
143
+ };
package/lib/index.js ADDED
@@ -0,0 +1,4 @@
1
+ 'use strict';
2
+
3
+ require('babel-polyfill');
4
+ module.exports = require('./mitmproxy');
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,107 @@
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 through = require('through2');
8
+ var zlib = require('zlib');
9
+ var url = require('url');
10
+
11
+ var httpUtil = {};
12
+ httpUtil.isGzip = function (res) {
13
+ var contentEncoding = res.headers['content-encoding'];
14
+ return !!(contentEncoding && contentEncoding.toLowerCase() == 'gzip');
15
+ };
16
+ httpUtil.isHtml = function (res) {
17
+ var contentType = res.headers['content-type'];
18
+ return typeof contentType != 'undefined' && /text\/html|application\/xhtml\+xml/.test(contentType);
19
+ };
20
+
21
+ function injectContentIntoHtmlHead(html, content) {
22
+ html = html.replace(/(<\/head>)/i, function (match) {
23
+ return content + match;
24
+ });
25
+ return html;
26
+ }
27
+
28
+ function injectContentIntoHtmlBody(html, content) {
29
+ html = html.replace(/(<\/body>)/i, function (match) {
30
+ return content + match;
31
+ });
32
+ return html;
33
+ }
34
+
35
+ function chunkReplace(_this, chunk, enc, callback, headContent, bodyContent) {
36
+ var chunkString = chunk.toString();
37
+ if (headContent) {
38
+ chunkString = injectScriptIntoHtmlHead(chunkString, headContent);
39
+ }
40
+ if (bodyContent) {
41
+ chunkString = injectContentIntoHtmlBody(chunkString, bodyContent);
42
+ }
43
+ _this.push(new Buffer(chunkString));
44
+ callback();
45
+ }
46
+
47
+ module.exports = function () {
48
+ function InjectHtmlPlugin(_ref) {
49
+ var head = _ref.head,
50
+ body = _ref.body;
51
+
52
+ _classCallCheck(this, InjectHtmlPlugin);
53
+
54
+ this.head = head;
55
+ this.body = body;
56
+ }
57
+
58
+ _createClass(InjectHtmlPlugin, [{
59
+ key: 'responseInterceptor',
60
+ value: function responseInterceptor(req, res, proxyReq, proxyRes, ssl, next) {
61
+
62
+ if (!this.head && !this.body) {
63
+ next();
64
+ return;
65
+ }
66
+
67
+ var isHtml = httpUtil.isHtml(proxyRes);
68
+ var contentLengthIsZero = function () {
69
+ return proxyRes.headers['content-length'] == 0;
70
+ }();
71
+ if (!isHtml || contentLengthIsZero) {
72
+ next();
73
+ } else {
74
+ Object.keys(proxyRes.headers).forEach(function (key) {
75
+ if (proxyRes.headers[key] != undefined) {
76
+ var newkey = key.replace(/^[a-z]|-[a-z]/g, function (match) {
77
+ return match.toUpperCase();
78
+ });
79
+ var newkey = key;
80
+ if (isHtml && key === 'content-length') {
81
+ // do nothing
82
+ } else {
83
+ res.setHeader(newkey, proxyRes.headers[key]);
84
+ }
85
+ }
86
+ });
87
+
88
+ res.writeHead(proxyRes.statusCode);
89
+
90
+ var isGzip = httpUtil.isGzip(proxyRes);
91
+
92
+ if (isGzip) {
93
+ proxyRes.pipe(new zlib.Gunzip()).pipe(through(function (chunk, enc, callback) {
94
+ chunkReplace(this, chunk, enc, callback, this.head, this.body);
95
+ })).pipe(new zlib.Gzip()).pipe(res);
96
+ } else {
97
+ proxyRes.pipe(through(function (chunk, enc, callback) {
98
+ chunkReplace(this, chunk, enc, callback, this.head, this.body);
99
+ })).pipe(res);
100
+ }
101
+ }
102
+ next();
103
+ }
104
+ }]);
105
+
106
+ return InjectHtmlPlugin;
107
+ }();
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,40 @@
1
+ 'use strict';
2
+
3
+ var net = require('net');
4
+ var url = require('url');
5
+ var colors = require('colors');
6
+
7
+ var localIP = '127.0.0.1';
8
+ // create connectHandler function
9
+ module.exports = function createConnectHandler(sslConnectInterceptor, fakeServerCenter) {
10
+
11
+ // return
12
+ return function connectHandler(req, cltSocket, head) {
13
+
14
+ var srvUrl = url.parse('https://' + req.url);
15
+
16
+ if (typeof sslConnectInterceptor === 'function' && sslConnectInterceptor.call(null, req, cltSocket, head)) {
17
+ fakeServerCenter.getServerPromise(srvUrl.hostname, srvUrl.port).then(function (serverObj) {
18
+ connect(req, cltSocket, head, localIP, serverObj.port);
19
+ }, function (e) {
20
+ console.error(e);
21
+ });
22
+ } else {
23
+ connect(req, cltSocket, head, srvUrl.hostname, srvUrl.port);
24
+ }
25
+ };
26
+ };
27
+
28
+ function connect(req, cltSocket, head, hostname, port) {
29
+ // tunneling https
30
+ var proxySocket = net.connect(port, hostname, function () {
31
+ cltSocket.write('HTTP/1.1 200 Connection Established\r\n' + 'Proxy-agent: node-mitmproxy\r\n' + '\r\n');
32
+ proxySocket.write(head);
33
+ proxySocket.pipe(cltSocket);
34
+ cltSocket.pipe(proxySocket);
35
+ });
36
+ proxySocket.on('error', function (e) {
37
+ console.log(colors.red(e));
38
+ });
39
+ return proxySocket;
40
+ }
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ var config = require('../common/config');
4
+ var fs = require('fs');
5
+ var path = require('path');
6
+ var forge = require('node-forge');
7
+ var FakeServersCenter = require('../tls/FakeServersCenter');
8
+ var colors = require('colors');
9
+
10
+ module.exports = function createFakeServerCenter(_ref) {
11
+ var caCertPath = _ref.caCertPath,
12
+ caKeyPath = _ref.caKeyPath,
13
+ requestHandler = _ref.requestHandler,
14
+ upgradeHandler = _ref.upgradeHandler,
15
+ getCertSocketTimeout = _ref.getCertSocketTimeout;
16
+
17
+ var caCert;
18
+ var caKey;
19
+ try {
20
+ fs.accessSync(caCertPath, fs.F_OK);
21
+ fs.accessSync(caKeyPath, fs.F_OK);
22
+ var caCertPem = fs.readFileSync(caCertPath);
23
+ var caKeyPem = fs.readFileSync(caKeyPath);
24
+ caCert = forge.pki.certificateFromPem(caCertPem);
25
+ caKey = forge.pki.privateKeyFromPem(caKeyPem);
26
+ } catch (e) {
27
+ console.log(colors.red('Can not find `CA certificate` or `CA key`.'), e);
28
+ process.exit(1);
29
+ }
30
+
31
+ return new FakeServersCenter({
32
+ caCert: caCert,
33
+ caKey: caKey,
34
+ maxLength: 100,
35
+ requestHandler: requestHandler,
36
+ upgradeHandler: upgradeHandler,
37
+ getCertSocketTimeout: getCertSocketTimeout
38
+ });
39
+ };