mirror of
https://github.com/alibaba/anyproxy.git
synced 2025-04-23 15:51:25 +00:00
Merge pull request #325 from alibaba/ws-port-integrate
create the wsServer based on webserver, no need for a seperate `wsPort`
This commit is contained in:
commit
4f438d6398
@ -79,8 +79,7 @@ const options = {
|
|||||||
rule: require('myRuleModule'),
|
rule: require('myRuleModule'),
|
||||||
webInterface: {
|
webInterface: {
|
||||||
enable: true,
|
enable: true,
|
||||||
webPort: 8002,
|
webPort: 8002
|
||||||
wsPort: 8003,
|
|
||||||
},
|
},
|
||||||
throttle: 10000,
|
throttle: 10000,
|
||||||
forceProxyHttps: false,
|
forceProxyHttps: false,
|
||||||
|
@ -78,8 +78,7 @@ const options = {
|
|||||||
rule: require('myRuleModule'),
|
rule: require('myRuleModule'),
|
||||||
webInterface: {
|
webInterface: {
|
||||||
enable: true,
|
enable: true,
|
||||||
webPort: 8002,
|
webPort: 8002
|
||||||
wsPort: 8003,
|
|
||||||
},
|
},
|
||||||
throttle: 10000,
|
throttle: 10000,
|
||||||
forceProxyHttps: false,
|
forceProxyHttps: false,
|
||||||
|
@ -14,7 +14,6 @@ const express = require('express'),
|
|||||||
wsServer = require('./wsServer'),
|
wsServer = require('./wsServer'),
|
||||||
juicer = require('juicer'),
|
juicer = require('juicer'),
|
||||||
ip = require('ip'),
|
ip = require('ip'),
|
||||||
co = require('co'),
|
|
||||||
compress = require('compression');
|
compress = require('compression');
|
||||||
|
|
||||||
const packageJson = require('../package.json');
|
const packageJson = require('../package.json');
|
||||||
@ -33,7 +32,6 @@ class webInterface extends events.EventEmitter {
|
|||||||
*
|
*
|
||||||
* @param {object} config
|
* @param {object} config
|
||||||
* @param {number} config.webPort
|
* @param {number} config.webPort
|
||||||
* @param {number} config.wsPort
|
|
||||||
* @param {object} recorder
|
* @param {object} recorder
|
||||||
*
|
*
|
||||||
* @memberOf webInterface
|
* @memberOf webInterface
|
||||||
@ -48,328 +46,281 @@ class webInterface extends events.EventEmitter {
|
|||||||
self.recorder = recorder;
|
self.recorder = recorder;
|
||||||
self.config = config || {};
|
self.config = config || {};
|
||||||
|
|
||||||
self.app = null;
|
self.app = this.getServer();
|
||||||
self.server = null;
|
self.server = null;
|
||||||
self.wsServer = null;
|
self.wsServer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
/**
|
||||||
|
* get the express server
|
||||||
|
*/
|
||||||
|
getServer() {
|
||||||
const self = this;
|
const self = this;
|
||||||
const recorder = self.recorder;
|
const recorder = self.recorder;
|
||||||
let wsPort;
|
const ipAddress = ip.address(),
|
||||||
|
// userRule = proxyInstance.proxyRule,
|
||||||
|
webBasePath = 'web';
|
||||||
|
let ruleSummary = '';
|
||||||
|
let customMenu = [];
|
||||||
|
|
||||||
return co(function *() {
|
try {
|
||||||
// determine ws port
|
ruleSummary = ''; //userRule.summary();
|
||||||
wsPort = self.config.wsPort ? self.config.wsPort : yield util.getFreePort();
|
customMenu = ''; // userRule._getCustomMenu();
|
||||||
}).then(() => {
|
} catch (e) { }
|
||||||
const ipAddress = ip.address(),
|
|
||||||
// userRule = proxyInstance.proxyRule,
|
|
||||||
webBasePath = 'web';
|
|
||||||
let ruleSummary = '';
|
|
||||||
let customMenu = [];
|
|
||||||
|
|
||||||
try {
|
const myAbsAddress = 'http://' + ipAddress + ':' + self.webPort + '/',
|
||||||
ruleSummary = ''; //userRule.summary();
|
staticDir = path.join(__dirname, '../', webBasePath);
|
||||||
customMenu = ''; // userRule._getCustomMenu();
|
|
||||||
} catch (e) { }
|
|
||||||
|
|
||||||
const myAbsAddress = 'http://' + ipAddress + ':' + self.webPort + '/',
|
const app = express();
|
||||||
staticDir = path.join(__dirname, '../', webBasePath);
|
app.use(compress()); //invoke gzip
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
res.setHeader('note', 'THIS IS A REQUEST FROM ANYPROXY WEB INTERFACE');
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
|
||||||
const app = express();
|
app.get('/latestLog', (req, res) => {
|
||||||
app.use(compress()); //invoke gzip
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
app.use((req, res, next) => {
|
recorder.getRecords(null, 10000, (err, docs) => {
|
||||||
res.setHeader('note', 'THIS IS A REQUEST FROM ANYPROXY WEB INTERFACE');
|
if (err) {
|
||||||
return next();
|
res.end(err.toString());
|
||||||
|
} else {
|
||||||
|
res.json(docs);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
app.use(bodyParser.json());
|
});
|
||||||
|
|
||||||
app.get('/latestLog', (req, res) => {
|
app.get('/downloadBody', (req, res) => {
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
const query = req.query;
|
||||||
recorder.getRecords(null, 10000, (err, docs) => {
|
recorder.getDecodedBody(query.id, (err, result) => {
|
||||||
if (err) {
|
if (err || !result || !result.content) {
|
||||||
res.end(err.toString());
|
res.json({});
|
||||||
} else {
|
} else if (result.mime) {
|
||||||
res.json(docs);
|
if (query.raw === 'true') {
|
||||||
|
//TODO : cache query result
|
||||||
|
res.type(result.mime).end(result.content);
|
||||||
|
} else if (query.download === 'true') {
|
||||||
|
res.setHeader('Content-disposition', `attachment; filename=${result.fileName}`);
|
||||||
|
res.setHeader('Content-type', result.mime);
|
||||||
|
res.end(result.content);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/downloadBody', (req, res) => {
|
|
||||||
const query = req.query;
|
|
||||||
recorder.getDecodedBody(query.id, (err, result) => {
|
|
||||||
if (err || !result || !result.content) {
|
|
||||||
res.json({});
|
|
||||||
} else if (result.mime) {
|
|
||||||
if (query.raw === 'true') {
|
|
||||||
//TODO : cache query result
|
|
||||||
res.type(result.mime).end(result.content);
|
|
||||||
} else if (query.download === 'true') {
|
|
||||||
res.setHeader('Content-disposition', `attachment; filename=${result.fileName}`);
|
|
||||||
res.setHeader('Content-type', result.mime);
|
|
||||||
res.end(result.content);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res.json({
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/fetchBody', (req, res) => {
|
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
||||||
const query = req.query;
|
|
||||||
if (query && query.id) {
|
|
||||||
recorder.getDecodedBody(query.id, (err, result) => {
|
|
||||||
// 返回下载信息
|
|
||||||
const _resDownload = function (isDownload) {
|
|
||||||
isDownload = typeof isDownload === 'boolean' ? isDownload : true;
|
|
||||||
res.json({
|
|
||||||
id: query.id,
|
|
||||||
type: result.type,
|
|
||||||
method: result.meethod,
|
|
||||||
fileName: result.fileName,
|
|
||||||
ref: `/downloadBody?id=${query.id}&download=${isDownload}&raw=${!isDownload}`
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 返回内容
|
|
||||||
const _resContent = () => {
|
|
||||||
if (util.getByteSize(result.content || '') > MAX_CONTENT_SIZE) {
|
|
||||||
_resDownload(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
id: query.id,
|
|
||||||
type: result.type,
|
|
||||||
method: result.method,
|
|
||||||
resBody: result.content
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (err || !result) {
|
|
||||||
res.json({});
|
|
||||||
} else if (result.statusCode === 200 && result.mime) {
|
|
||||||
if (result.type === 'json' ||
|
|
||||||
result.mime.indexOf('text') === 0 ||
|
|
||||||
// deal with 'application/x-javascript' and 'application/javascript'
|
|
||||||
result.mime.indexOf('javascript') > -1) {
|
|
||||||
_resContent();
|
|
||||||
} else if (result.type === 'image') {
|
|
||||||
_resDownload(false);
|
|
||||||
} else {
|
|
||||||
_resDownload(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_resContent();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.end({});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/fetchReqBody', (req, res) => {
|
|
||||||
const query = req.query;
|
|
||||||
if (query && query.id) {
|
|
||||||
recorder.getSingleRecord(query.id, (err, doc) => {
|
|
||||||
if (err || !doc[0]) {
|
|
||||||
console.error(err);
|
|
||||||
res.end('');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.setHeader('Content-disposition', `attachment; filename=request_${query.id}_body.txt`);
|
|
||||||
res.setHeader('Content-type', 'text/plain');
|
|
||||||
res.end(doc[0].reqBody);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.end('');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/fetchWsMessages', (req, res) => {
|
|
||||||
const query = req.query;
|
|
||||||
if (query && query.id) {
|
|
||||||
recorder.getDecodedWsMessage(query.id, (err, messages) => {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
res.json([]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.json(messages);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.json([]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/fetchCrtFile', (req, res) => {
|
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
||||||
const _crtFilePath = certMgr.getRootCAFilePath();
|
|
||||||
if (_crtFilePath) {
|
|
||||||
res.setHeader('Content-Type', 'application/x-x509-ca-cert');
|
|
||||||
res.setHeader('Content-Disposition', 'attachment; filename="rootCA.crt"');
|
|
||||||
res.end(fs.readFileSync(_crtFilePath, { encoding: null }));
|
|
||||||
} else {
|
|
||||||
res.setHeader('Content-Type', 'text/html');
|
|
||||||
res.end('can not file rootCA ,plase use <strong>anyproxy --root</strong> to generate one');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//make qr code
|
|
||||||
app.get('/qr', (req, res) => {
|
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
||||||
const qr = qrCode.qrcode(4, 'M'),
|
|
||||||
targetUrl = myAbsAddress;
|
|
||||||
qr.addData(targetUrl);
|
|
||||||
qr.make();
|
|
||||||
const qrImageTag = qr.createImgTag(4);
|
|
||||||
const resDom = '<a href="__url"> __img <br> click or scan qr code to start client </a>'.replace(/__url/, targetUrl).replace(/__img/, qrImageTag);
|
|
||||||
res.setHeader('Content-Type', 'text/html');
|
|
||||||
res.end(resDom);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.get('/api/getQrCode', (req, res) => {
|
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
||||||
const qr = qrCode.qrcode(4, 'M'),
|
|
||||||
targetUrl = myAbsAddress + 'fetchCrtFile';
|
|
||||||
|
|
||||||
qr.addData(targetUrl);
|
|
||||||
qr.make();
|
|
||||||
const qrImageTag = qr.createImgTag(4);
|
|
||||||
|
|
||||||
// resDom = '<a href="__url"> __img <br> click or scan qr code to download rootCA.crt </a>'.replace(/__url/,targetUrl).replace(/__img/,qrImageTag);
|
|
||||||
// res.setHeader("Content-Type", "text/html");
|
|
||||||
// res.end(resDom);
|
|
||||||
|
|
||||||
const isRootCAFileExists = certMgr.isRootCAFileExists();
|
|
||||||
res.json({
|
|
||||||
status: 'success',
|
|
||||||
url: targetUrl,
|
|
||||||
isRootCAFileExists,
|
|
||||||
qrImgDom: qrImageTag
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// response init data
|
|
||||||
app.get('/api/getInitData', (req, res) => {
|
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
||||||
const rootCAExists = certMgr.isRootCAFileExists();
|
|
||||||
const rootDirPath = certMgr.getRootDirPath();
|
|
||||||
const interceptFlag = false; //proxyInstance.getInterceptFlag(); TODO
|
|
||||||
const globalProxyFlag = false; // TODO: proxyInstance.getGlobalProxyFlag();
|
|
||||||
res.json({
|
|
||||||
status: 'success',
|
|
||||||
rootCAExists,
|
|
||||||
rootCADirPath: rootDirPath,
|
|
||||||
currentInterceptFlag: interceptFlag,
|
|
||||||
currentGlobalProxyFlag: globalProxyFlag,
|
|
||||||
ruleSummary: ruleSummary || '',
|
|
||||||
ipAddress: util.getAllIpAddress(),
|
|
||||||
port: '', //proxyInstance.proxyPort, // TODO
|
|
||||||
wsPort,
|
|
||||||
appVersion: packageJson.version
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/generateRootCA', (req, res) => {
|
|
||||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
||||||
const rootExists = certMgr.isRootCAFileExists();
|
|
||||||
if (!rootExists) {
|
|
||||||
certMgr.generateRootCA(() => {
|
|
||||||
res.json({
|
|
||||||
status: 'success',
|
|
||||||
code: 'done'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
res.json({
|
res.json({
|
||||||
status: 'success',
|
|
||||||
code: 'root_ca_exists'
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// should not be available in in-build version
|
app.get('/fetchBody', (req, res) => {
|
||||||
// app.post('/api/toggleInterceptHttps', (req, res) => {
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
// const rootExists = certMgr.isRootCAFileExists();
|
const query = req.query;
|
||||||
// if (!rootExists) {
|
if (query && query.id) {
|
||||||
// certMgr.generateRootCA(() => {
|
recorder.getDecodedBody(query.id, (err, result) => {
|
||||||
// proxyInstance.setIntercept(req.body.flag);
|
// 返回下载信息
|
||||||
// // Also inform the web if RootCa exists
|
const _resDownload = function (isDownload) {
|
||||||
// res.json({
|
isDownload = typeof isDownload === 'boolean' ? isDownload : true;
|
||||||
// status: 'success',
|
res.json({
|
||||||
// rootExists
|
id: query.id,
|
||||||
// });
|
type: result.type,
|
||||||
// });
|
method: result.meethod,
|
||||||
// } else {
|
fileName: result.fileName,
|
||||||
// proxyInstance.setIntercept(req.body.flag);
|
ref: `/downloadBody?id=${query.id}&download=${isDownload}&raw=${!isDownload}`
|
||||||
// res.json({
|
});
|
||||||
// status: 'success',
|
|
||||||
// rootExists
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// app.post('/api/toggleGlobalProxy', (req, res) => {
|
|
||||||
// const flag = req.body.flag;
|
|
||||||
// let result = {};
|
|
||||||
// result = flag ? proxyInstance.enableGlobalProxy() : proxyInstance.disableGlobalProxy();
|
|
||||||
|
|
||||||
// if (result.status) {
|
|
||||||
// res.json({
|
|
||||||
// status: 'failed',
|
|
||||||
// errorMsg: result.stdout
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// res.json({
|
|
||||||
// status: 'success',
|
|
||||||
// isWindows: /^win/.test(process.platform)
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
app.use((req, res, next) => {
|
|
||||||
const indexTpl = fs.readFileSync(path.join(staticDir, '/index.html'), { encoding: 'utf8' }),
|
|
||||||
opt = {
|
|
||||||
rule: ruleSummary || '',
|
|
||||||
customMenu: customMenu || [],
|
|
||||||
wsPort,
|
|
||||||
ipAddress: ipAddress || '127.0.0.1'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (url.parse(req.url).pathname === '/') {
|
// 返回内容
|
||||||
res.setHeader('Content-Type', 'text/html');
|
const _resContent = () => {
|
||||||
res.end(juicer(indexTpl, opt));
|
if (util.getByteSize(result.content || '') > MAX_CONTENT_SIZE) {
|
||||||
} else {
|
_resDownload(true);
|
||||||
next();
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
app.use(express.static(staticDir));
|
res.json({
|
||||||
|
id: query.id,
|
||||||
|
type: result.type,
|
||||||
|
method: result.method,
|
||||||
|
resBody: result.content
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
//plugin from rule file
|
if (err || !result) {
|
||||||
const server = app.listen(self.webPort);
|
res.json({});
|
||||||
|
} else if (result.statusCode === 200 && result.mime) {
|
||||||
self.app = app;
|
if (result.type === 'json' ||
|
||||||
self.server = server;
|
result.mime.indexOf('text') === 0 ||
|
||||||
}).then(() => {
|
// deal with 'application/x-javascript' and 'application/javascript'
|
||||||
// start ws server
|
result.mime.indexOf('javascript') > -1) {
|
||||||
self.wsServer = new wsServer({
|
_resContent();
|
||||||
port: wsPort
|
} else if (result.type === 'image') {
|
||||||
}, recorder);
|
_resDownload(false);
|
||||||
|
} else {
|
||||||
return self.wsServer.start();
|
_resDownload(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_resContent();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.end({});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get('/fetchReqBody', (req, res) => {
|
||||||
|
const query = req.query;
|
||||||
|
if (query && query.id) {
|
||||||
|
recorder.getSingleRecord(query.id, (err, doc) => {
|
||||||
|
if (err || !doc[0]) {
|
||||||
|
console.error(err);
|
||||||
|
res.end('');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.setHeader('Content-disposition', `attachment; filename=request_${query.id}_body.txt`);
|
||||||
|
res.setHeader('Content-type', 'text/plain');
|
||||||
|
res.end(doc[0].reqBody);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.end('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/fetchWsMessages', (req, res) => {
|
||||||
|
const query = req.query;
|
||||||
|
if (query && query.id) {
|
||||||
|
recorder.getDecodedWsMessage(query.id, (err, messages) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.json([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.json(messages);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.json([]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/fetchCrtFile', (req, res) => {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
const _crtFilePath = certMgr.getRootCAFilePath();
|
||||||
|
if (_crtFilePath) {
|
||||||
|
res.setHeader('Content-Type', 'application/x-x509-ca-cert');
|
||||||
|
res.setHeader('Content-Disposition', 'attachment; filename="rootCA.crt"');
|
||||||
|
res.end(fs.readFileSync(_crtFilePath, { encoding: null }));
|
||||||
|
} else {
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
res.end('can not file rootCA ,plase use <strong>anyproxy --root</strong> to generate one');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//make qr code
|
||||||
|
app.get('/qr', (req, res) => {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
const qr = qrCode.qrcode(4, 'M'),
|
||||||
|
targetUrl = myAbsAddress;
|
||||||
|
qr.addData(targetUrl);
|
||||||
|
qr.make();
|
||||||
|
const qrImageTag = qr.createImgTag(4);
|
||||||
|
const resDom = '<a href="__url"> __img <br> click or scan qr code to start client </a>'.replace(/__url/, targetUrl).replace(/__img/, qrImageTag);
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
res.end(resDom);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/api/getQrCode', (req, res) => {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
const qr = qrCode.qrcode(4, 'M'),
|
||||||
|
targetUrl = myAbsAddress + 'fetchCrtFile';
|
||||||
|
|
||||||
|
qr.addData(targetUrl);
|
||||||
|
qr.make();
|
||||||
|
const qrImageTag = qr.createImgTag(4);
|
||||||
|
|
||||||
|
// resDom = '<a href="__url"> __img <br> click or scan qr code to download rootCA.crt </a>'.replace(/__url/,targetUrl).replace(/__img/,qrImageTag);
|
||||||
|
// res.setHeader("Content-Type", "text/html");
|
||||||
|
// res.end(resDom);
|
||||||
|
|
||||||
|
const isRootCAFileExists = certMgr.isRootCAFileExists();
|
||||||
|
res.json({
|
||||||
|
status: 'success',
|
||||||
|
url: targetUrl,
|
||||||
|
isRootCAFileExists,
|
||||||
|
qrImgDom: qrImageTag
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// response init data
|
||||||
|
app.get('/api/getInitData', (req, res) => {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
const rootCAExists = certMgr.isRootCAFileExists();
|
||||||
|
const rootDirPath = certMgr.getRootDirPath();
|
||||||
|
const interceptFlag = false; //proxyInstance.getInterceptFlag(); TODO
|
||||||
|
const globalProxyFlag = false; // TODO: proxyInstance.getGlobalProxyFlag();
|
||||||
|
res.json({
|
||||||
|
status: 'success',
|
||||||
|
rootCAExists,
|
||||||
|
rootCADirPath: rootDirPath,
|
||||||
|
currentInterceptFlag: interceptFlag,
|
||||||
|
currentGlobalProxyFlag: globalProxyFlag,
|
||||||
|
ruleSummary: ruleSummary || '',
|
||||||
|
ipAddress: util.getAllIpAddress(),
|
||||||
|
port: '', //proxyInstance.proxyPort, // TODO
|
||||||
|
appVersion: packageJson.version
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/generateRootCA', (req, res) => {
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
const rootExists = certMgr.isRootCAFileExists();
|
||||||
|
if (!rootExists) {
|
||||||
|
certMgr.generateRootCA(() => {
|
||||||
|
res.json({
|
||||||
|
status: 'success',
|
||||||
|
code: 'done'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.json({
|
||||||
|
status: 'success',
|
||||||
|
code: 'root_ca_exists'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
const indexTpl = fs.readFileSync(path.join(staticDir, '/index.html'), { encoding: 'utf8' }),
|
||||||
|
opt = {
|
||||||
|
rule: ruleSummary || '',
|
||||||
|
customMenu: customMenu || [],
|
||||||
|
ipAddress: ipAddress || '127.0.0.1'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (url.parse(req.url).pathname === '/') {
|
||||||
|
res.setHeader('Content-Type', 'text/html');
|
||||||
|
res.end(juicer(indexTpl, opt));
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.use(express.static(staticDir));
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
const self = this;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
self.server = self.app.listen(self.webPort);
|
||||||
|
self.wsServer = new wsServer({
|
||||||
|
server: self.server
|
||||||
|
}, self.recorder);
|
||||||
|
self.wsServer.start();
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
this.server && this.server.close();
|
this.server && this.server.close();
|
||||||
this.wsServer && this.wsServer.closeAll();
|
this.wsServer && this.wsServer.closeAll();
|
||||||
|
|
||||||
this.server = null;
|
this.server = null;
|
||||||
this.wsServer = null;
|
this.wsServer = null;
|
||||||
this.proxyInstance = null;
|
this.proxyInstance = null;
|
||||||
|
@ -46,14 +46,14 @@ function resToMsg(msg, recorder, cb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//config.port
|
//config.server
|
||||||
|
|
||||||
class wsServer {
|
class wsServer {
|
||||||
constructor(config, recorder) {
|
constructor(config, recorder) {
|
||||||
if (!recorder) {
|
if (!recorder) {
|
||||||
throw new Error('proxy recorder is required');
|
throw new Error('proxy recorder is required');
|
||||||
} else if (!config || !config.port) {
|
} else if (!config || !config.server) {
|
||||||
throw new Error('config.port is required');
|
throw new Error('config.server is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
@ -68,11 +68,11 @@ class wsServer {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
//web socket interface
|
//web socket interface
|
||||||
const wss = new WebSocketServer({
|
const wss = new WebSocketServer({
|
||||||
port: config.port,
|
server: config.server,
|
||||||
clientTracking: true,
|
clientTracking: true,
|
||||||
}, resolve);
|
});
|
||||||
|
resolve();
|
||||||
logUtil.printLog(`WebSoket setup at port ${config.port} `, logUtil.T_DEBUG);
|
|
||||||
// the queue of the messages to be delivered
|
// the queue of the messages to be delivered
|
||||||
let messageQueue = [];
|
let messageQueue = [];
|
||||||
// the flat to indicate wheter to broadcast the record
|
// the flat to indicate wheter to broadcast the record
|
||||||
|
@ -6,8 +6,7 @@ const options = {
|
|||||||
rule: null,
|
rule: null,
|
||||||
webInterface: {
|
webInterface: {
|
||||||
enable: true,
|
enable: true,
|
||||||
webPort: 8002,
|
webPort: 8002
|
||||||
wsPort: 8003,
|
|
||||||
},
|
},
|
||||||
throttle: 10000,
|
throttle: 10000,
|
||||||
forceProxyHttps: true,
|
forceProxyHttps: true,
|
||||||
|
1
proxy.js
1
proxy.js
@ -310,7 +310,6 @@ class ProxyServer extends ProxyCore {
|
|||||||
* @param {object} [config.webInterface] - config of the web interface
|
* @param {object} [config.webInterface] - config of the web interface
|
||||||
* @param {boolean} [config.webInterface.enable=false] - if web interface is enabled
|
* @param {boolean} [config.webInterface.enable=false] - if web interface is enabled
|
||||||
* @param {number} [config.webInterface.webPort=8002] - http port of the web interface
|
* @param {number} [config.webInterface.webPort=8002] - http port of the web interface
|
||||||
* @param {number} [config.webInterface.wsPort] - web socket port of the web interface
|
|
||||||
*/
|
*/
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
// prepare a recorder
|
// prepare a recorder
|
||||||
|
@ -16,8 +16,7 @@ describe('AnyProxy.proxyServer basic test', () => {
|
|||||||
rule: null,
|
rule: null,
|
||||||
webInterface: {
|
webInterface: {
|
||||||
enable: true,
|
enable: true,
|
||||||
webPort: 8002,
|
webPort: 8002
|
||||||
wsPort: 8003,
|
|
||||||
},
|
},
|
||||||
throttle: 10000,
|
throttle: 10000,
|
||||||
forceProxyHttps: false,
|
forceProxyHttps: false,
|
||||||
|
@ -11,7 +11,6 @@ const DEFAULT_OPTIONS = {
|
|||||||
webInterface: {
|
webInterface: {
|
||||||
enable: true,
|
enable: true,
|
||||||
webPort: 8002, // optional, port for web interface
|
webPort: 8002, // optional, port for web interface
|
||||||
wsPort: 8003, // optional, internal port for web socket
|
|
||||||
},
|
},
|
||||||
wsIntercept: true,
|
wsIntercept: true,
|
||||||
throttle: 10000, // optional, speed limit in kb/s
|
throttle: 10000, // optional, speed limit in kb/s
|
||||||
|
@ -11,7 +11,6 @@ export const FETCH_MAPPED_CONFIG = 'FETCH_MAPPED_CONFIG';
|
|||||||
export const UPDATE_LOCAL_MAPPED_CONFIG = 'UPDATE_LOCAL_MAPPED_CONFIG';
|
export const UPDATE_LOCAL_MAPPED_CONFIG = 'UPDATE_LOCAL_MAPPED_CONFIG';
|
||||||
export const UPDATE_REMOTE_MAPPED_CONFIG = 'UPDATE_REMOTE_MAPPED_CONFIG';
|
export const UPDATE_REMOTE_MAPPED_CONFIG = 'UPDATE_REMOTE_MAPPED_CONFIG';
|
||||||
export const UPDATE_ACTIVE_RECORD_ITEM = 'UPDATE_ACTIVE_RECORD_ITEM';
|
export const UPDATE_ACTIVE_RECORD_ITEM = 'UPDATE_ACTIVE_RECORD_ITEM';
|
||||||
export const UPDATE_GLOBAL_WSPORT = 'UPDATE_GLOBAL_WSPORT';
|
|
||||||
|
|
||||||
export const TOGGLE_REMOTE_INTERCEPT_HTTPS = 'TOGGLE_REMOTE_INTERCEPT_HTTPS';
|
export const TOGGLE_REMOTE_INTERCEPT_HTTPS = 'TOGGLE_REMOTE_INTERCEPT_HTTPS';
|
||||||
export const UPDATE_LOCAL_INTERCEPT_HTTPS_FLAG = 'UPDATE_LOCAL_INTERCEPT_HTTPS_FLAG';
|
export const UPDATE_LOCAL_INTERCEPT_HTTPS_FLAG = 'UPDATE_LOCAL_INTERCEPT_HTTPS_FLAG';
|
||||||
@ -202,13 +201,6 @@ export function updateIsRootCAExists(exists) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateGlobalWsPort(wsPort) {
|
|
||||||
return {
|
|
||||||
type: UPDATE_GLOBAL_WSPORT,
|
|
||||||
data: wsPort
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateFechingRecordStatus(isFetching) {
|
export function updateFechingRecordStatus(isFetching) {
|
||||||
return {
|
return {
|
||||||
type: UPDATE_FETCHING_RECORD_STATUS,
|
type: UPDATE_FETCHING_RECORD_STATUS,
|
||||||
|
@ -6,14 +6,14 @@ import { message } from 'antd';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiate a ws connection.
|
* Initiate a ws connection.
|
||||||
* The default pay `do-not-proxy` means the ws do not need to be proxied.
|
* The default path `do-not-proxy` means the ws do not need to be proxied.
|
||||||
* This is very important for AnyProxy its' own server, such as WEB UI, and the
|
* This is very important for AnyProxy‘s own server, such as WEB UI,
|
||||||
* websocket detail panel, to prevent a recursive proxy.
|
* and the websocket detail panel in it, to prevent a recursive proxy.
|
||||||
* @param {wsPort} wsPort the port of websocket
|
* @param {wsPort} wsPort the port of websocket
|
||||||
* @param {key} path the path of the ws url
|
* @param {key} path the path of the ws url
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export function initWs(wsPort = 8003, path = 'do-not-proxy') {
|
export function initWs(wsPort = location.port, path = 'do-not-proxy') {
|
||||||
if(!WebSocket){
|
if(!WebSocket){
|
||||||
throw (new Error('WebSocket is not supportted on this browser'));
|
throw (new Error('WebSocket is not supportted on this browser'));
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@ import {
|
|||||||
toggleRemoteGlobalProxyFlag,
|
toggleRemoteGlobalProxyFlag,
|
||||||
updateShouldClearRecord,
|
updateShouldClearRecord,
|
||||||
updateIsRootCAExists,
|
updateIsRootCAExists,
|
||||||
updateGlobalWsPort,
|
|
||||||
showFilter,
|
showFilter,
|
||||||
updateLocalAppVersion
|
updateLocalAppVersion
|
||||||
} from 'action/globalStatusAction';
|
} from 'action/globalStatusAction';
|
||||||
@ -141,14 +140,12 @@ class HeaderMenu extends React.Component {
|
|||||||
ruleSummary: response.ruleSummary,
|
ruleSummary: response.ruleSummary,
|
||||||
rootCADirPath: response.rootCADirPath,
|
rootCADirPath: response.rootCADirPath,
|
||||||
ipAddress: response.ipAddress,
|
ipAddress: response.ipAddress,
|
||||||
port: response.port,
|
port: response.port
|
||||||
wsPort: response.wsPort
|
|
||||||
});
|
});
|
||||||
this.props.dispatch(updateLocalInterceptHttpsFlag(response.currentInterceptFlag));
|
this.props.dispatch(updateLocalInterceptHttpsFlag(response.currentInterceptFlag));
|
||||||
this.props.dispatch(updateLocalGlobalProxyFlag(response.currentGlobalProxyFlag));
|
this.props.dispatch(updateLocalGlobalProxyFlag(response.currentGlobalProxyFlag));
|
||||||
this.props.dispatch(updateLocalAppVersion(response.appVersion));
|
this.props.dispatch(updateLocalAppVersion(response.appVersion));
|
||||||
this.props.dispatch(updateIsRootCAExists(response.rootCAExists));
|
this.props.dispatch(updateIsRootCAExists(response.rootCAExists));
|
||||||
this.props.dispatch(updateGlobalWsPort(response.wsPort));
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
@ -66,7 +66,7 @@ class RecordDetail extends React.Component {
|
|||||||
|
|
||||||
getWsMessageDiv(recordDetail) {
|
getWsMessageDiv(recordDetail) {
|
||||||
const { globalStatus } = this.props;
|
const { globalStatus } = this.props;
|
||||||
return <RecordWsMessageDetail recordDetail={recordDetail} wsPort={globalStatus.wsPort} />;
|
return <RecordWsMessageDetail recordDetail={recordDetail} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRecordContentDiv(recordDetail = {}, fetchingRecord) {
|
getRecordContentDiv(recordDetail = {}, fetchingRecord) {
|
||||||
|
@ -49,8 +49,7 @@ class RecordWsMessageDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
recordDetail: PropTypes.object,
|
recordDetail: PropTypes.object
|
||||||
wsPort: PropTypes.number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleRefresh () {
|
toggleRefresh () {
|
||||||
@ -112,13 +111,11 @@ class RecordWsMessageDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { wsPort, recordDetail } = this.props;
|
const { recordDetail } = this.props;
|
||||||
if (!wsPort) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.refreshPage();
|
this.refreshPage();
|
||||||
|
|
||||||
this.wsClient = initWs(wsPort);
|
this.wsClient = initWs();
|
||||||
this.wsClient.addEventListener('message', this.onMessageHandler);
|
this.wsClient.addEventListener('message', this.onMessageHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,12 +140,11 @@ class WsListener extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
initWs() {
|
initWs() {
|
||||||
const { wsPort } = this.props.globalStatus;
|
if (this.state.wsInited) {
|
||||||
if (!wsPort || this.state.wsInited) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.state.wsInited = true;
|
this.state.wsInited = true;
|
||||||
const wsClient = initWs(wsPort);
|
const wsClient = initWs();
|
||||||
wsClient.onmessage = this.onWsMessage;
|
wsClient.onmessage = this.onWsMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ const defaultStatus = {
|
|||||||
showNewRecordTip: false,
|
showNewRecordTip: false,
|
||||||
isRootCAFileExists: false,
|
isRootCAFileExists: false,
|
||||||
fetchingRecord: false,
|
fetchingRecord: false,
|
||||||
wsPort: null,
|
|
||||||
mappedConfig:[] // configured map config
|
mappedConfig:[] // configured map config
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -45,7 +44,6 @@ import {
|
|||||||
UPDATE_APP_VERSION,
|
UPDATE_APP_VERSION,
|
||||||
UPDATE_IS_ROOTCA_EXISTS,
|
UPDATE_IS_ROOTCA_EXISTS,
|
||||||
UPDATE_SHOW_NEW_RECORD_TIP,
|
UPDATE_SHOW_NEW_RECORD_TIP,
|
||||||
UPDATE_GLOBAL_WSPORT,
|
|
||||||
UPDATE_FETCHING_RECORD_STATUS
|
UPDATE_FETCHING_RECORD_STATUS
|
||||||
} from 'action/globalStatusAction';
|
} from 'action/globalStatusAction';
|
||||||
|
|
||||||
@ -209,12 +207,6 @@ function requestListReducer(state = defaultStatus, action) {
|
|||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
case UPDATE_GLOBAL_WSPORT: {
|
|
||||||
const newState = Object.assign({}, state);
|
|
||||||
newState.wsPort = action.data;
|
|
||||||
return newState;
|
|
||||||
}
|
|
||||||
|
|
||||||
case UPDATE_FETCHING_RECORD_STATUS: {
|
case UPDATE_FETCHING_RECORD_STATUS: {
|
||||||
const newState = Object.assign({}, state);
|
const newState = Object.assign({}, state);
|
||||||
newState.fetchingRecord = action.data;
|
newState.fetchingRecord = action.data;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user