mirror of
https://github.com/wuchangming/spy-debugger.git
synced 2026-01-18 14:29:45 +00:00
213 lines
8.6 KiB
JavaScript
213 lines
8.6 KiB
JavaScript
'use strict';
|
|
|
|
var url = require('url');
|
|
var mitmProxy = require('node-mitmproxy');
|
|
var httpUtil = require('../util/httpUtil');
|
|
var zlib = require('zlib');
|
|
var through = require('through2');
|
|
var config = require('../config/config');
|
|
var htmlUtil = require('../util/htmlUtil');
|
|
var path = require('path');
|
|
var fs = require('fs');
|
|
var colors = require('colors');
|
|
var charset = require('charset');
|
|
var iconv = require('iconv-lite');
|
|
var jschardet = require('jschardet');
|
|
var domain = require('domain');
|
|
var childProcess = require('child_process');
|
|
|
|
var d = domain.create();
|
|
d.on('error', function (err) {
|
|
console.log(err.message);
|
|
});
|
|
module.exports = {
|
|
createProxy: function createProxy(_ref) {
|
|
var injectScriptTag = _ref.injectScriptTag,
|
|
_ref$port = _ref.port,
|
|
port = _ref$port === undefined ? 9888 : _ref$port,
|
|
weinrePort = _ref.weinrePort,
|
|
_ref$autoDetectBrowse = _ref.autoDetectBrowser,
|
|
autoDetectBrowser = _ref$autoDetectBrowse === undefined ? true : _ref$autoDetectBrowse,
|
|
_externalProxy = _ref.externalProxy,
|
|
successCB = _ref.successCB,
|
|
cache = _ref.cache;
|
|
|
|
var createMitmProxy = function createMitmProxy() {
|
|
mitmProxy.createProxy({
|
|
externalProxy: function externalProxy(req, ssl) {
|
|
// ignore weixin mmtls
|
|
var headers = req.headers;
|
|
if (headers['upgrade'] && headers['upgrade'] === 'mmtls') {
|
|
return '';
|
|
} else {
|
|
return _externalProxy;
|
|
}
|
|
},
|
|
port: port,
|
|
getCertSocketTimeout: 3 * 1000,
|
|
sslConnectInterceptor: function sslConnectInterceptor(req, cltSocket, head) {
|
|
var srvUrl = url.parse('https://' + req.url);
|
|
|
|
// 只拦截浏览器的https请求
|
|
if (!autoDetectBrowser || req.headers && req.headers['user-agent'] && (/Mozilla/.test(req.headers['user-agent']) || /com.apple.WebKit.Networking/i.test(req.headers['user-agent']))) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
requestInterceptor: function requestInterceptor(rOptions, req, res, ssl, next) {
|
|
var rPath;
|
|
if (rOptions.path) {
|
|
rPath = url.parse(rOptions.path).path;
|
|
} else {
|
|
rOptions.path = '/';
|
|
}
|
|
|
|
if (rOptions.headers.host === config.SPY_DEBUGGER_DOMAIN && rPath === '/cert' || rOptions.headers.host === config.SPY_DEBUGGER_SHORT_DOMAIN) {
|
|
var userHome = process.env.HOME || process.env.USERPROFILE;
|
|
var certPath = path.resolve(userHome, './node-mitmproxy/node-mitmproxy.ca.crt');
|
|
try {
|
|
var fileString = fs.readFileSync(certPath);
|
|
res.setHeader('Content-Type', 'application/x-x509-ca-cert');
|
|
res.setHeader("Content-Disposition", "attachment;filename=node-mitmproxy.ca.crt");
|
|
res.end(fileString.toString());
|
|
} catch (e) {
|
|
console.log(e);
|
|
res.end('please create certificate first!!');
|
|
}
|
|
next();
|
|
return;
|
|
}
|
|
if (rOptions.headers.host === config.SPY_WEINRE_DOMAIN) {
|
|
rOptions.protocol = 'http:';
|
|
rOptions.hostname = '127.0.0.1';
|
|
rOptions.port = weinrePort;
|
|
// trick for non-transparent proxy
|
|
rOptions.path = rPath;
|
|
rOptions.agent = false;
|
|
}
|
|
// delete Accept-Encoding
|
|
delete rOptions.headers['accept-encoding'];
|
|
|
|
// no cache
|
|
if (!cache) {
|
|
delete rOptions.headers['if-modified-since'];
|
|
delete rOptions.headers['last-modified'];
|
|
delete rOptions.headers['if-none-match'];
|
|
}
|
|
|
|
next();
|
|
},
|
|
responseInterceptor: function responseInterceptor(req, res, proxyReq, proxyRes, ssl, next) {
|
|
var isHtml = httpUtil.isHtml(proxyRes);
|
|
var contentLengthIsZero = function () {
|
|
return proxyRes.headers['content-length'] == 0;
|
|
}();
|
|
if (!isHtml || contentLengthIsZero) {
|
|
next();
|
|
} else {
|
|
Object.keys(proxyRes.headers).forEach(function (key) {
|
|
if (proxyRes.headers[key] != undefined) {
|
|
var newkey = key.replace(/^[a-z]|-[a-z]/g, function (match) {
|
|
return match.toUpperCase();
|
|
});
|
|
var newkey = key;
|
|
|
|
if (isHtml && (key === 'content-length' || key === 'content-security-policy')) {
|
|
// do nothing
|
|
} else {
|
|
res.setHeader(newkey, proxyRes.headers[key]);
|
|
}
|
|
}
|
|
});
|
|
|
|
res.writeHead(proxyRes.statusCode);
|
|
|
|
var isGzip = httpUtil.isGzip(proxyRes);
|
|
|
|
var chunks = [];
|
|
proxyRes.on('data', function (chunk) {
|
|
chunks.push(chunk);
|
|
}).on('end', function () {
|
|
var allChunk = Buffer.concat(chunks);
|
|
|
|
res.end(chunkReplace(allChunk, injectScriptTag, proxyRes));
|
|
});
|
|
}
|
|
next();
|
|
}
|
|
});
|
|
};
|
|
|
|
if (!_externalProxy) {
|
|
d.run(function () {
|
|
var ports = void 0;
|
|
|
|
var childProxy = childProcess.fork(__dirname + '/externalChildProcess');
|
|
childProxy.send({
|
|
type: 'start'
|
|
});
|
|
childProxy.on('message', function (externalProxyPorts) {
|
|
ports = externalProxyPorts;
|
|
var externalProxyPort = externalProxyPorts.port;
|
|
var externalProxyWebPort = externalProxyPorts.webPort;
|
|
_externalProxy = 'http://127.0.0.1:' + externalProxyPort;
|
|
createMitmProxy();
|
|
successCB(externalProxyPorts);
|
|
});
|
|
var restartFun = function restartFun() {
|
|
console.log(colors.yellow('anyproxy\u5F02\u5E38\u9000\u51FA\uFF0C\u5C1D\u8BD5\u91CD\u542F'));
|
|
var childProxy = childProcess.fork(__dirname + '/externalChildProcess');
|
|
childProxy.send({
|
|
type: 'restart',
|
|
ports: ports
|
|
});
|
|
childProxy.on('exit', function (e) {
|
|
restartFun();
|
|
});
|
|
};
|
|
childProxy.on('exit', function (e) {
|
|
restartFun();
|
|
});
|
|
});
|
|
} else {
|
|
createMitmProxy();
|
|
successCB(null);
|
|
}
|
|
}
|
|
};
|
|
function chunkReplace(chunk, injectScriptTag, proxyRes) {
|
|
var _charset;
|
|
try {
|
|
_charset = charset(proxyRes, chunk) || jschardet.detect(chunk).encoding.toLowerCase();
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
var chunkString;
|
|
if (_charset != null && _charset != 'utf-8') {
|
|
try {
|
|
chunkString = iconv.decode(chunk, _charset);
|
|
} catch (e) {
|
|
console.error(e);
|
|
chunkString = iconv.decode(chunk, 'utf-8');
|
|
}
|
|
} else {
|
|
chunkString = chunk.toString();
|
|
}
|
|
|
|
var newChunkString = htmlUtil.injectScriptIntoHtml(chunkString, injectScriptTag);
|
|
|
|
var buffer;
|
|
if (_charset != null && _charset != 'utf-8') {
|
|
try {
|
|
buffer = iconv.encode(newChunkString, _charset);
|
|
} catch (e) {
|
|
console.error(e);
|
|
buffer = iconv.encode(newChunkString, 'utf-8');
|
|
}
|
|
} else {
|
|
buffer = new Buffer(newChunkString);
|
|
}
|
|
|
|
return buffer;
|
|
} |