Merge pull request #401 from alibaba/ca_helper

Add ca helper when run anyproxy -i
This commit is contained in:
Otto Mao 2018-08-06 11:36:25 +08:00 committed by GitHub
commit 0621dadf28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 208 additions and 99 deletions

View File

@ -4,9 +4,11 @@
const program = require('commander'), const program = require('commander'),
color = require('colorful'), color = require('colorful'),
co = require('co'),
packageInfo = require('../package.json'), packageInfo = require('../package.json'),
ruleLoader = require('../lib/ruleLoader'),
util = require('../lib/util'), util = require('../lib/util'),
rootCACheck = require('./rootCaCheck'),
startServer = require('./startServer'),
logUtil = require('../lib/log'); logUtil = require('../lib/log');
program program
@ -33,85 +35,20 @@ if (program.clear) {
process.exit(0); process.exit(0);
}); });
} else { } else {
const AnyProxy = require('../proxy.js'); co(function *() {
let proxyServer; if (program.silent) {
logUtil.setPrintStatus(false);
if (program.silent) {
logUtil.setPrintStatus(false);
}
// load rule module
new Promise((resolve, reject) => {
if (program.rule) {
resolve(ruleLoader.requireModule(program.rule));
} else {
resolve(null);
}
})
.catch(e => {
logUtil.printLog('Failed to load rule file', logUtil.T_ERR);
logUtil.printLog(e, logUtil.T_ERR);
process.exit();
})
//start proxy
.then(ruleModule => {
proxyServer = new AnyProxy.ProxyServer({
type: 'http',
port: program.port || 8001,
throttle: program.throttle,
rule: ruleModule,
webInterface: {
enable: true,
webPort: program.web,
},
wsIntercept: program.wsIntercept,
forceProxyHttps: program.intercept,
dangerouslyIgnoreUnauthorized: !!program.ignoreUnauthorizedSsl,
silent: program.silent
});
// proxyServer.on('ready', () => {});
proxyServer.start();
})
.catch(e => {
logUtil.printLog(e, logUtil.T_ERR);
if (e && e.code) {
logUtil.printLog('code ' + e.code, logUtil.T_ERR);
}
logUtil.printLog(e.stack, logUtil.T_ERR);
});
process.on('exit', (code) => {
if (code > 0) {
logUtil.printLog('AnyProxy is about to exit with code: ' + code, logUtil.T_ERR);
} }
process.exit(); if (program.intercept) {
}); try {
yield rootCACheck();
//exit cause ctrl+c } catch (e) {
process.on('SIGINT', () => { console.error(e);
try {
proxyServer && proxyServer.close();
} catch (e) {
console.error(e);
}
process.exit();
});
process.on('uncaughtException', (err) => {
let errorTipText = 'got an uncaught exception, is there anything goes wrong in your rule file ?\n';
try {
if (err && err.stack) {
errorTipText += err.stack;
} else {
errorTipText += err;
} }
} catch (e) {} }
logUtil.printLog(errorTipText, logUtil.T_ERR);
try { return startServer(program);
proxyServer && proxyServer.close(); })
} catch (e) {}
process.exit();
});
} }

33
bin/rootCACheck.js Normal file
View File

@ -0,0 +1,33 @@
/**
* check if root CA exists and installed
* will prompt to generate when needed
*/
const thunkify = require('thunkify');
const AnyProxy = require('../proxy');
const logUtil = require('../lib/log');
const certMgr = AnyProxy.utils.certMgr;
function checkRootCAExists() {
return certMgr.isRootCAFileExists();
}
module.exports = function *() {
try {
if (!checkRootCAExists()) {
logUtil.warn('Missing root CA, generating now');
yield thunkify(certMgr.generateRootCA)();
yield certMgr.trustRootCA();
} else {
const isCATrusted = yield thunkify(certMgr.ifRootCATrusted)();
if (!isCATrusted) {
logUtil.warn('ROOT CA NOT INSTALLED YET');
yield certMgr.trustRootCA();
}
}
} catch (e) {
console.error(e);
}
};

86
bin/startServer.js Normal file
View File

@ -0,0 +1,86 @@
/**
* start the AnyProxy server
*/
const ruleLoader = require('../lib/ruleLoader');
const logUtil = require('../lib/log');
const AnyProxy = require('../proxy');
module.exports = function startServer(program) {
let proxyServer;
// load rule module
new Promise((resolve, reject) => {
if (program.rule) {
resolve(ruleLoader.requireModule(program.rule));
} else {
resolve(null);
}
})
.catch(e => {
logUtil.printLog('Failed to load rule file', logUtil.T_ERR);
logUtil.printLog(e, logUtil.T_ERR);
process.exit();
})
//start proxy
.then(ruleModule => {
proxyServer = new AnyProxy.ProxyServer({
type: 'http',
port: program.port || 8001,
throttle: program.throttle,
rule: ruleModule,
webInterface: {
enable: true,
webPort: program.web,
},
wsIntercept: program.wsIntercept,
forceProxyHttps: program.intercept,
dangerouslyIgnoreUnauthorized: !!program.ignoreUnauthorizedSsl,
silent: program.silent
});
// proxyServer.on('ready', () => {});
proxyServer.start();
})
.catch(e => {
logUtil.printLog(e, logUtil.T_ERR);
if (e && e.code) {
logUtil.printLog('code ' + e.code, logUtil.T_ERR);
}
logUtil.printLog(e.stack, logUtil.T_ERR);
});
process.on('exit', (code) => {
if (code > 0) {
logUtil.printLog('AnyProxy is about to exit with code: ' + code, logUtil.T_ERR);
}
process.exit();
});
//exit cause ctrl+c
process.on('SIGINT', () => {
try {
proxyServer && proxyServer.close();
} catch (e) {
console.error(e);
}
process.exit();
});
process.on('uncaughtException', (err) => {
let errorTipText = 'got an uncaught exception, is there anything goes wrong in your rule file ?\n';
try {
if (err && err.stack) {
errorTipText += err.stack;
} else {
errorTipText += err;
}
} catch (e) { }
logUtil.printLog(errorTipText, logUtil.T_ERR);
try {
proxyServer && proxyServer.close();
} catch (e) { }
process.exit();
});
}

View File

@ -1,11 +1,16 @@
'use strict' 'use strict'
const util = require('./util');
const EasyCert = require('node-easy-cert'); const EasyCert = require('node-easy-cert');
const co = require('co'); const co = require('co');
const os = require('os');
const inquirer = require('inquirer');
const util = require('./util');
const logUtil = require('./log');
const options = { const options = {
rootDirPath: util.getAnyProxyPath('certificates'), rootDirPath: util.getAnyProxyPath('certificates'),
inMemory: false,
defaultCertAttrs: [ defaultCertAttrs: [
{ name: 'countryName', value: 'CN' }, { name: 'countryName', value: 'CN' },
{ name: 'organizationName', value: 'AnyProxy' }, { name: 'organizationName', value: 'AnyProxy' },
@ -54,4 +59,45 @@ crtMgr.getCAStatus = function *() {
}); });
} }
/**
* trust the root ca by command
*/
crtMgr.trustRootCA = function *() {
const platform = os.platform();
const rootCAPath = crtMgr.getRootCAFilePath();
const trustInquiry = [
{
type: 'list',
name: 'trustCA',
message: 'The rootCA is not trusted yet, install it to the trust store now?',
choices: ['Yes', "No, I'll do it myself"]
}
];
if (platform === 'darwin') {
const answer = yield inquirer.prompt(trustInquiry);
if (answer.trustCA === 'Yes') {
logUtil.info('About to trust the root CA, this may requires your password');
// https://ss64.com/osx/security-cert.html
const result = util.execScriptSync(`sudo security add-trusted-cert -d -k /Library/Keychains/System.keychain ${rootCAPath}`);
if (result.status === 0) {
logUtil.info('Root CA install, you are ready to intercept the https now');
} else {
console.error(result);
logUtil.info('Failed to trust the root CA, please trust it manually');
util.guideToHomePage();
}
} else {
logUtil.info('Please trust the root CA manually so https interception works');
util.guideToHomePage();
}
}
if (/^win/.test(process.platform)) {
logUtil.info('You can install the root CA manually.');
}
logUtil.info('The root CA file path is: ' + crtMgr.getRootCAFilePath());
}
module.exports = crtMgr; module.exports = crtMgr;

View File

@ -58,7 +58,7 @@ function printLog(content, type) {
return; return;
} }
console.error(color.magenta(`[AnyProxy WARN][${timeString}]: ` + content)); console.error(color.yellow(`[AnyProxy WARN][${timeString}]: ` + content));
break; break;
} }
@ -89,7 +89,7 @@ module.exports.warn = (content) => {
}; };
module.exports.error = (content) => { module.exports.error = (content) => {
printLog(content, LogLevelMap.error); printLog(content, LogLevelMap.system_error);
}; };
module.exports.ruleError = (content) => { module.exports.ruleError = (content) => {

View File

@ -4,7 +4,7 @@ const fs = require('fs'),
path = require('path'), path = require('path'),
mime = require('mime-types'), mime = require('mime-types'),
color = require('colorful'), color = require('colorful'),
crypto = require('crypto'), child_process = require('child_process'),
Buffer = require('buffer').Buffer, Buffer = require('buffer').Buffer,
logUtil = require('./log'); logUtil = require('./log');
const networkInterfaces = require('os').networkInterfaces(); const networkInterfaces = require('os').networkInterfaces();
@ -216,6 +216,8 @@ function deleteFolderContentsRecursive(dirPath, ifClearFolderItself) {
throw new Error('can_not_delete_this_dir'); throw new Error('can_not_delete_this_dir');
} }
logUtil.info('==>>> clearing cache ', dirPath);
if (fs.existsSync(dirPath)) { if (fs.existsSync(dirPath)) {
fs.readdirSync(dirPath).forEach((file) => { fs.readdirSync(dirPath).forEach((file) => {
const curPath = path.join(dirPath, file); const curPath = path.join(dirPath, file);
@ -307,17 +309,22 @@ module.exports.isIpDomain = function (domain) {
return ipReg.test(domain); return ipReg.test(domain);
}; };
/** module.exports.execScriptSync = function (cmd) {
* To generic a Sec-WebSocket-Accept value let stdout,
* 1. append the `Sec-WebSocket-Key` request header with `matic string` status = 0;
* 2. get sha1 hash of the string try {
* 3. get base64 of the sha1 hash stdout = child_process.execSync(cmd);
*/ } catch (err) {
module.exports.genericWsSecAccept = function (wsSecKey) { stdout = err.stdout;
// the string to generate the Sec-WebSocket-Accept status = err.status;
const magicString = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; }
const targetString = `${wsSecKey}${magicString}`;
const shasum = crypto.createHash('sha1'); return {
shasum.update(targetString); stdout: stdout.toString(),
return shasum.digest('base64'); status
} };
};
module.exports.guideToHomePage = function () {
logUtil.info('Refer to http://anyproxy.io for more detail');
};

View File

@ -1,6 +1,6 @@
{ {
"name": "anyproxy", "name": "anyproxy",
"version": "4.0.10", "version": "4.0.11",
"description": "A fully configurable HTTP/HTTPS proxy in Node.js", "description": "A fully configurable HTTP/HTTPS proxy in Node.js",
"main": "proxy.js", "main": "proxy.js",
"bin": { "bin": {
@ -35,6 +35,7 @@
"request": "^2.74.0", "request": "^2.74.0",
"stream-throttle": "^0.1.3", "stream-throttle": "^0.1.3",
"svg-inline-react": "^1.0.2", "svg-inline-react": "^1.0.2",
"thunkify": "^2.1.2",
"whatwg-fetch": "^1.0.0", "whatwg-fetch": "^1.0.0",
"ws": "^5.1.0" "ws": "^5.1.0"
}, },
@ -68,7 +69,6 @@
"koa-send": "^3.2.0", "koa-send": "^3.2.0",
"less": "^2.7.1", "less": "^2.7.1",
"less-loader": "^2.2.3", "less-loader": "^2.2.3",
"memwatch-next": "^0.3.0",
"node-simhash": "^0.1.0", "node-simhash": "^0.1.0",
"nodeunit": "^0.9.1", "nodeunit": "^0.9.1",
"phantom": "^4.0.0", "phantom": "^4.0.0",