mirror of
https://github.com/alibaba/anyproxy.git
synced 2025-05-10 14:58:27 +00:00
feat: refact the remaining files into TS
This commit is contained in:
parent
bcb7451579
commit
0385096857
@ -8,11 +8,13 @@ import util from './util';
|
||||
import logUtil from './log';
|
||||
|
||||
declare interface ICertMgr {
|
||||
ifRootCAFileExists?: boolean;
|
||||
generateRootCA?: ( cb: (error: boolean, keyPath: string, crtPath: string) => void ) => void;
|
||||
getCAStatus?: () => Generator;
|
||||
trustRootCA?: () => Generator;
|
||||
getRootCAFilePath?: () => string;
|
||||
ifRootCAFileExists?: () => boolean;
|
||||
isRootCAFileExists?: () => boolean;
|
||||
getRootDirPath?: () => string;
|
||||
getCertificate?: (serverName: string, cb: (err: Error, key: string, crt: string) => void) => void;
|
||||
}
|
||||
|
||||
|
15
lib/proxy/index.ts
Normal file
15
lib/proxy/index.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import ProxyCore from './proxyCore';
|
||||
import ProxyServer from './proxyServer';
|
||||
import WebInterface from '../webInterface';
|
||||
import Recorder from '../recorder';
|
||||
import certMgr from '../certMgr';
|
||||
|
||||
|
||||
module.exports.ProxyCore = ProxyCore;
|
||||
module.exports.ProxyServer = ProxyServer;
|
||||
module.exports.ProxyRecorder = Recorder;
|
||||
module.exports.ProxyWebServer = WebInterface;
|
||||
module.exports.utils = {
|
||||
systemProxyMgr: require('../systemProxyMgr'),
|
||||
certMgr,
|
||||
};
|
@ -1,41 +1,28 @@
|
||||
'use strict';
|
||||
/*tslint:disable:max-line-length */
|
||||
|
||||
const http = require('http'),
|
||||
https = require('https'),
|
||||
async = require('async'),
|
||||
color = require('colorful'),
|
||||
certMgr = require('./certMgr').default,
|
||||
Recorder = require('./recorder').default,
|
||||
logUtil = require('./log').default,
|
||||
util = require('./util').default,
|
||||
events = require('events'),
|
||||
co = require('co'),
|
||||
WebInterface = require('./webInterface'),
|
||||
wsServerMgr = require('./wsServerMgr').default,
|
||||
ThrottleGroup = require('stream-throttle').ThrottleGroup;
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
import * as async from 'async';
|
||||
import * as color from 'colorful';
|
||||
import * as events from 'events';
|
||||
import * as throttle from 'stream-throttle';
|
||||
import * as co from 'co';
|
||||
import certMgr from '../certMgr';
|
||||
import Recorder from '../recorder';
|
||||
import logUtil from '../log';
|
||||
import util from '../util';
|
||||
import RequestHandler from '../requestHandler';
|
||||
import wsServerMgr from '../wsServerMgr';
|
||||
import WebInterface from '../webInterface';
|
||||
|
||||
// const memwatch = require('memwatch-next');
|
||||
declare type TSyncTaskCb = (err: Error) => void;
|
||||
|
||||
// setInterval(() => {
|
||||
// console.log(process.memoryUsage());
|
||||
// const rss = Math.ceil(process.memoryUsage().rss / 1000 / 1000);
|
||||
// console.log('Program is using ' + rss + ' mb of Heap.');
|
||||
// }, 1000);
|
||||
const ThrottleGroup = throttle.ThrottleGroup;
|
||||
|
||||
// memwatch.on('stats', (info) => {
|
||||
// console.log('gc !!');
|
||||
// console.log(process.memoryUsage());
|
||||
// const rss = Math.ceil(process.memoryUsage().rss / 1000 / 1000);
|
||||
// console.log('GC !! Program is using ' + rss + ' mb of Heap.');
|
||||
|
||||
// // var heapUsed = Math.ceil(process.memoryUsage().heapUsed / 1000);
|
||||
// // console.log("Program is using " + heapUsed + " kb of Heap.");
|
||||
// // console.log(info);
|
||||
// });
|
||||
|
||||
const T_TYPE_HTTP = 'http',
|
||||
T_TYPE_HTTPS = 'https',
|
||||
DEFAULT_TYPE = T_TYPE_HTTP;
|
||||
const T_TYPE_HTTP = 'http';
|
||||
const T_TYPE_HTTPS = 'https';
|
||||
const DEFAULT_TYPE = T_TYPE_HTTP;
|
||||
|
||||
const PROXY_STATUS_INIT = 'INIT';
|
||||
const PROXY_STATUS_READY = 'READY';
|
||||
@ -47,25 +34,24 @@ const PROXY_STATUS_CLOSED = 'CLOSED';
|
||||
* @extends {events.EventEmitter}
|
||||
*/
|
||||
class ProxyCore extends events.EventEmitter {
|
||||
|
||||
private socketIndex: number;
|
||||
private status: 'INIT' | 'READY' | 'CLOSED';
|
||||
private proxyPort: string;
|
||||
private proxyType: 'http' | 'https';
|
||||
protected proxyHostName: string;
|
||||
public recorder: Recorder;
|
||||
private httpProxyServer: http.Server | https.Server;
|
||||
protected webServerInstance: WebInterface;
|
||||
private requestHandler: RequestHandler;
|
||||
private proxyRule: AnyProxyRule;
|
||||
private socketPool: {
|
||||
[key: string]: http.IncomingMessage;
|
||||
};
|
||||
/**
|
||||
* Creates an instance of ProxyCore.
|
||||
*
|
||||
* @param {object} config - configs
|
||||
* @param {number} config.port - port of the proxy server
|
||||
* @param {object} [config.rule=null] - rule module to use
|
||||
* @param {string} [config.type=http] - type of the proxy server, could be 'http' or 'https'
|
||||
* @param {strign} [config.hostname=localhost] - host name of the proxy server, required when this is an https proxy
|
||||
* @param {number} [config.throttle] - speed limit in kb/s
|
||||
* @param {boolean} [config.forceProxyHttps=false] - if proxy all https requests
|
||||
* @param {boolean} [config.silent=false] - if keep the console silent
|
||||
* @param {boolean} [config.dangerouslyIgnoreUnauthorized=false] - if ignore unauthorized server response
|
||||
* @param {object} [config.recorder] - recorder to use
|
||||
* @param {boolean} [config.wsIntercept] - whether intercept websocket
|
||||
*
|
||||
* @memberOf ProxyCore
|
||||
*/
|
||||
constructor(config) {
|
||||
constructor(config: AnyProxyConfig) {
|
||||
super();
|
||||
config = config || {};
|
||||
|
||||
@ -114,12 +100,12 @@ class ProxyCore extends events.EventEmitter {
|
||||
this.recorder = config.recorder;
|
||||
|
||||
// init request handler
|
||||
const RequestHandler = util.freshRequire('./requestHandler').default;
|
||||
this.requestHandler = new RequestHandler({
|
||||
const RequestHandlerClass = (util.freshRequire('./requestHandler') as any).default;
|
||||
this.requestHandler = new RequestHandlerClass({
|
||||
wsIntercept: config.wsIntercept,
|
||||
httpServerPort: config.port, // the http server port for http proxy
|
||||
forceProxyHttps: !!config.forceProxyHttps,
|
||||
dangerouslyIgnoreUnauthorized: !!config.dangerouslyIgnoreUnauthorized
|
||||
dangerouslyIgnoreUnauthorized: !!config.dangerouslyIgnoreUnauthorized,
|
||||
}, this.proxyRule, this.recorder);
|
||||
}
|
||||
|
||||
@ -133,7 +119,7 @@ class ProxyCore extends events.EventEmitter {
|
||||
* @returns undefined
|
||||
* @memberOf ProxyCore
|
||||
*/
|
||||
handleExistConnections(socket) {
|
||||
private handleExistConnections(socket: http.IncomingMessage): void {
|
||||
const self = this;
|
||||
self.socketIndex ++;
|
||||
const key = `socketIndex_${self.socketIndex}`;
|
||||
@ -151,7 +137,7 @@ class ProxyCore extends events.EventEmitter {
|
||||
*
|
||||
* @memberOf ProxyCore
|
||||
*/
|
||||
start() {
|
||||
public start(): ProxyCore {
|
||||
const self = this;
|
||||
self.socketIndex = 0;
|
||||
self.socketPool = {};
|
||||
@ -161,8 +147,8 @@ class ProxyCore extends events.EventEmitter {
|
||||
}
|
||||
async.series(
|
||||
[
|
||||
//creat proxy server
|
||||
function (callback) {
|
||||
// creat proxy server
|
||||
function(callback: TSyncTaskCb): void {
|
||||
if (self.proxyType === T_TYPE_HTTPS) {
|
||||
certMgr.getCertificate(self.proxyHostName, (err, keyContent, crtContent) => {
|
||||
if (err) {
|
||||
@ -170,7 +156,7 @@ class ProxyCore extends events.EventEmitter {
|
||||
} else {
|
||||
self.httpProxyServer = https.createServer({
|
||||
key: keyContent,
|
||||
cert: crtContent
|
||||
cert: crtContent,
|
||||
}, self.requestHandler.userRequestHandler);
|
||||
callback(null);
|
||||
}
|
||||
@ -181,17 +167,17 @@ class ProxyCore extends events.EventEmitter {
|
||||
}
|
||||
},
|
||||
|
||||
//handle CONNECT request for https over http
|
||||
function (callback) {
|
||||
// handle CONNECT request for https over http
|
||||
function(callback: TSyncTaskCb): void {
|
||||
self.httpProxyServer.on('connect', self.requestHandler.connectReqHandler);
|
||||
|
||||
callback(null);
|
||||
},
|
||||
|
||||
function (callback) {
|
||||
function(callback: TSyncTaskCb): void {
|
||||
wsServerMgr.getWsServer({
|
||||
server: self.httpProxyServer,
|
||||
connHandler: self.requestHandler.wsHandler
|
||||
connHandler: self.requestHandler.wsHandler,
|
||||
});
|
||||
// remember all sockets, so we can destory them when call the method 'close';
|
||||
self.httpProxyServer.on('connection', (socket) => {
|
||||
@ -200,14 +186,14 @@ class ProxyCore extends events.EventEmitter {
|
||||
callback(null);
|
||||
},
|
||||
|
||||
//start proxy server
|
||||
function (callback) {
|
||||
// start proxy server
|
||||
function(callback: TSyncTaskCb): void {
|
||||
self.httpProxyServer.listen(self.proxyPort);
|
||||
callback(null);
|
||||
},
|
||||
],
|
||||
|
||||
//final callback
|
||||
// final callback
|
||||
(err, result) => {
|
||||
if (!err) {
|
||||
const tipText = (self.proxyType === T_TYPE_HTTP ? 'Http' : 'Https') + ' proxy started on port ' + self.proxyPort;
|
||||
@ -221,7 +207,7 @@ class ProxyCore extends events.EventEmitter {
|
||||
let ruleSummaryString = '';
|
||||
const ruleSummary = this.proxyRule.summary;
|
||||
if (ruleSummary) {
|
||||
co(function *() {
|
||||
co(function *(): Generator {
|
||||
if (typeof ruleSummary === 'string') {
|
||||
ruleSummaryString = ruleSummary;
|
||||
} else {
|
||||
@ -239,10 +225,10 @@ class ProxyCore extends events.EventEmitter {
|
||||
logUtil.printLog(color.red(tipText), logUtil.T_ERR);
|
||||
logUtil.printLog(err, logUtil.T_ERR);
|
||||
self.emit('error', {
|
||||
error: err
|
||||
error: err,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return self;
|
||||
@ -256,24 +242,34 @@ class ProxyCore extends events.EventEmitter {
|
||||
*
|
||||
* @memberOf ProxyCore
|
||||
*/
|
||||
close() {
|
||||
public close(): Promise<Error> {
|
||||
// clear recorder cache
|
||||
return new Promise((resolve) => {
|
||||
if (this.httpProxyServer) {
|
||||
// destroy conns & cltSockets when closing proxy server
|
||||
for (const connItem of this.requestHandler.conns) {
|
||||
const key = connItem[0];
|
||||
const conn = connItem[1];
|
||||
this.requestHandler.conns.forEach((conn, key) => {
|
||||
logUtil.printLog(`destorying https connection : ${key}`);
|
||||
conn.end();
|
||||
}
|
||||
});
|
||||
|
||||
for (const cltSocketItem of this.requestHandler.cltSockets) {
|
||||
const key = cltSocketItem[0];
|
||||
const cltSocket = cltSocketItem[1];
|
||||
this.requestHandler.cltSockets.forEach((cltSocket, key) => {
|
||||
logUtil.printLog(`endding https cltSocket : ${key}`);
|
||||
cltSocket.end();
|
||||
}
|
||||
});
|
||||
|
||||
// for (const connItem of this.requestHandler.conns) {
|
||||
// const key = connItem[0];
|
||||
// const conn = connItem[1];
|
||||
// logUtil.printLog(`destorying https connection : ${key}`);
|
||||
// conn.end();
|
||||
// }
|
||||
|
||||
// for (const cltSocketItem of this.requestHandler.cltSockets) {
|
||||
// const key = cltSocketItem[0];
|
||||
// const cltSocket = cltSocketItem[1];
|
||||
// logUtil.printLog(`endding https cltSocket : ${key}`);
|
||||
// cltSocket.end();
|
||||
// }
|
||||
|
||||
if (this.socketPool) {
|
||||
for (const key in this.socketPool) {
|
||||
@ -296,92 +292,8 @@ class ProxyCore extends events.EventEmitter {
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* start proxy server as well as recorder and webInterface
|
||||
*/
|
||||
class ProxyServer extends ProxyCore {
|
||||
/**
|
||||
*
|
||||
* @param {object} config - config
|
||||
* @param {object} [config.webInterface] - config of the web interface
|
||||
* @param {boolean} [config.webInterface.enable=false] - if web interface is enabled
|
||||
* @param {number} [config.webInterface.webPort=8002] - http port of the web interface
|
||||
*/
|
||||
constructor(config) {
|
||||
// prepare a recorder
|
||||
const recorder = new Recorder();
|
||||
const configForCore = Object.assign({
|
||||
recorder,
|
||||
}, config);
|
||||
|
||||
super(configForCore);
|
||||
|
||||
this.proxyWebinterfaceConfig = config.webInterface;
|
||||
this.recorder = recorder;
|
||||
this.webServerInstance = null;
|
||||
}
|
||||
|
||||
start() {
|
||||
// start web interface if neeeded
|
||||
if (this.proxyWebinterfaceConfig && this.proxyWebinterfaceConfig.enable) {
|
||||
this.webServerInstance = new WebInterface(this.proxyWebinterfaceConfig, this.recorder);
|
||||
// start web server
|
||||
this.webServerInstance.start().then(() => {
|
||||
// start proxy core
|
||||
super.start();
|
||||
})
|
||||
.catch((e) => {
|
||||
this.emit('error', e);
|
||||
});
|
||||
} else {
|
||||
super.start();
|
||||
}
|
||||
}
|
||||
|
||||
close() {
|
||||
return new Promise((resolve, reject) => {
|
||||
super.close()
|
||||
.then((error) => {
|
||||
if (error) {
|
||||
resolve(error);
|
||||
}
|
||||
});
|
||||
|
||||
if (this.recorder) {
|
||||
logUtil.printLog('clearing cache file...');
|
||||
this.recorder.clear();
|
||||
}
|
||||
const tmpWebServer = this.webServerInstance;
|
||||
this.recorder = null;
|
||||
this.webServerInstance = null;
|
||||
if (tmpWebServer) {
|
||||
logUtil.printLog('closing webserver...');
|
||||
tmpWebServer.close((error) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
logUtil.printLog(`proxy web server close FAILED: ${error.message}`, logUtil.T_ERR);
|
||||
} else {
|
||||
logUtil.printLog(`proxy web server closed at ${this.proxyHostName} : ${this.webPort}`);
|
||||
}
|
||||
|
||||
resolve(error);
|
||||
})
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.ProxyCore = ProxyCore;
|
||||
module.exports.ProxyServer = ProxyServer;
|
||||
module.exports.ProxyRecorder = Recorder;
|
||||
module.exports.ProxyWebServer = WebInterface;
|
||||
module.exports.utils = {
|
||||
systemProxyMgr: require('./systemProxyMgr'),
|
||||
certMgr,
|
||||
};
|
||||
export default ProxyCore;
|
87
lib/proxy/proxyServer.ts
Normal file
87
lib/proxy/proxyServer.ts
Normal file
@ -0,0 +1,87 @@
|
||||
'use strict';
|
||||
|
||||
import ProxyCore from './proxyCore.js';
|
||||
import Recorder from '../recorder';
|
||||
import WebInterface from '../webInterface';
|
||||
import logUtil from '../log';
|
||||
|
||||
/**
|
||||
* start proxy server as well as recorder and webInterface
|
||||
*/
|
||||
class ProxyServer extends ProxyCore {
|
||||
public proxyWebinterfaceConfig: any;
|
||||
/**
|
||||
*
|
||||
* @param {object} config - config
|
||||
* @param {object} [config.webInterface] - config of the web interface
|
||||
* @param {boolean} [config.webInterface.enable=false] - if web interface is enabled
|
||||
* @param {number} [config.webInterface.webPort=8002] - http port of the web interface
|
||||
*/
|
||||
constructor(config: AnyProxyConfig) {
|
||||
// prepare a recorder
|
||||
const recorder = new Recorder();
|
||||
const configForCore = Object.assign({
|
||||
recorder,
|
||||
}, config);
|
||||
|
||||
super(configForCore);
|
||||
|
||||
this.proxyWebinterfaceConfig = config.webInterface;
|
||||
this.recorder = recorder;
|
||||
this.webServerInstance = null;
|
||||
}
|
||||
|
||||
public start(): ProxyServer {
|
||||
// start web interface if neeeded
|
||||
if (this.proxyWebinterfaceConfig && this.proxyWebinterfaceConfig.enable) {
|
||||
this.webServerInstance = new WebInterface(this.proxyWebinterfaceConfig, this.recorder);
|
||||
// start web server
|
||||
this.webServerInstance.start().then(() => {
|
||||
// start proxy core
|
||||
super.start();
|
||||
})
|
||||
.catch((e) => {
|
||||
this.emit('error', e);
|
||||
});
|
||||
} else {
|
||||
super.start();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public close(): Promise<Error> {
|
||||
return new Promise((resolve, reject) => {
|
||||
super.close()
|
||||
.then((error) => {
|
||||
if (error) {
|
||||
resolve(error);
|
||||
}
|
||||
});
|
||||
|
||||
if (this.recorder) {
|
||||
logUtil.printLog('clearing cache file...');
|
||||
this.recorder.clear();
|
||||
}
|
||||
const tmpWebServer = this.webServerInstance;
|
||||
this.recorder = null;
|
||||
this.webServerInstance = null;
|
||||
if (tmpWebServer) {
|
||||
logUtil.printLog('closing webserver...');
|
||||
tmpWebServer.close((error) => {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
logUtil.printLog(`proxy web server close FAILED: ${error.message}`, logUtil.T_ERR);
|
||||
} else {
|
||||
logUtil.printLog(`proxy web server closed at ${this.proxyHostName} : ${this.proxyWebinterfaceConfig.webPort}`);
|
||||
}
|
||||
|
||||
resolve(error);
|
||||
});
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default ProxyServer;
|
@ -412,9 +412,11 @@ class RequestHandler {
|
||||
public dangerouslyIgnoreUnauthorized: boolean;
|
||||
public httpServerPort: string;
|
||||
public wsIntercept: boolean;
|
||||
public conns: Map<string, net.Socket>;
|
||||
public cltSockets: Map<string, net.Socket>;
|
||||
public connectReqHandler: () => void;
|
||||
private userRequestHandler: () => void;
|
||||
private wsHandler: (wsClient: WebSocket, wsReq: http.IncomingMessage) => void;
|
||||
public userRequestHandler: () => void;
|
||||
public wsHandler: (wsClient: WebSocket, wsReq: http.IncomingMessage) => void;
|
||||
private httpsServerMgr: HttpsServerMgr;
|
||||
/**
|
||||
* Creates an instance of RequestHandler.
|
||||
|
@ -309,7 +309,7 @@ function isFunc(source: object): boolean {
|
||||
* @param {object} content
|
||||
* @returns the size of the content
|
||||
*/
|
||||
function getByteSize(content: Buffer): number {
|
||||
function getByteSize(content: Buffer | string): number {
|
||||
return Buffer.byteLength(content);
|
||||
}
|
||||
|
||||
|
@ -2,22 +2,44 @@
|
||||
|
||||
const DEFAULT_WEB_PORT = 8002; // port for web interface
|
||||
|
||||
const express = require('express'),
|
||||
url = require('url'),
|
||||
bodyParser = require('body-parser'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
events = require('events'),
|
||||
qrCode = require('qrcode-npm'),
|
||||
util = require('./util').default,
|
||||
certMgr = require('./certMgr').default,
|
||||
wsServer = require('./wsServer'),
|
||||
juicer = require('juicer'),
|
||||
ip = require('ip'),
|
||||
compress = require('compression');
|
||||
import * as express from 'express';
|
||||
import * as url from 'url';
|
||||
import * as bodyParser from 'body-parser';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as events from 'events';
|
||||
import * as qrCode from 'qrcode-npm';
|
||||
import * as juicer from 'juicer';
|
||||
import * as ip from 'ip';
|
||||
import * as http from 'http';
|
||||
import * as compress from 'compression';
|
||||
import * as buffer from 'buffer';
|
||||
import util from './util';
|
||||
import certMgr from './certMgr';
|
||||
import WsServer from './wsServer';
|
||||
import Recorder from './recorder';
|
||||
import LogUtil from './log';
|
||||
|
||||
/*tslint:disable:no-var-requires*/
|
||||
const packageJson = require('../package.json');
|
||||
|
||||
// const express = require('express'),
|
||||
// url = require('url'),
|
||||
// bodyParser = require('body-parser'),
|
||||
// fs = require('fs'),
|
||||
// path = require('path'),
|
||||
// events = require('events'),
|
||||
// qrCode = require('qrcode-npm'),
|
||||
// util = require('./util').default,
|
||||
// certMgr = require('./certMgr').default,
|
||||
// wsServer = require('./wsServer'),
|
||||
// juicer = require('juicer'),
|
||||
// ip = require('ip'),
|
||||
// compress = require('compression');
|
||||
|
||||
// const packageJson = require('../package.json');
|
||||
|
||||
const Buffer = buffer.Buffer;
|
||||
const MAX_CONTENT_SIZE = 1024 * 2000; // 2000kb
|
||||
/**
|
||||
*
|
||||
@ -25,18 +47,13 @@ const MAX_CONTENT_SIZE = 1024 * 2000; // 2000kb
|
||||
* @class webInterface
|
||||
* @extends {events.EventEmitter}
|
||||
*/
|
||||
class webInterface extends events.EventEmitter {
|
||||
|
||||
/**
|
||||
* Creates an instance of webInterface.
|
||||
*
|
||||
* @param {object} config
|
||||
* @param {number} config.webPort
|
||||
* @param {object} recorder
|
||||
*
|
||||
* @memberOf webInterface
|
||||
*/
|
||||
constructor(config, recorder) {
|
||||
class WebInterface extends events.EventEmitter {
|
||||
public webPort: number;
|
||||
private recorder: Recorder;
|
||||
private app: Express.Application;
|
||||
private server: http.Server;
|
||||
private wsServer: WsServer;
|
||||
constructor(config: AnyProxyWebInterfaceConfig, recorder: Recorder) {
|
||||
if (!recorder) {
|
||||
throw new Error('recorder is required for web interface');
|
||||
}
|
||||
@ -44,7 +61,7 @@ class webInterface extends events.EventEmitter {
|
||||
const self = this;
|
||||
self.webPort = config.webPort || DEFAULT_WEB_PORT;
|
||||
self.recorder = recorder;
|
||||
self.config = config || {};
|
||||
// self.config = config || {};
|
||||
|
||||
self.app = this.getServer();
|
||||
self.server = null;
|
||||
@ -54,25 +71,25 @@ class webInterface extends events.EventEmitter {
|
||||
/**
|
||||
* get the express server
|
||||
*/
|
||||
getServer() {
|
||||
public getServer(): Express.Application {
|
||||
const self = this;
|
||||
const recorder = self.recorder;
|
||||
const ipAddress = ip.address(),
|
||||
const ipAddress = ip.address();
|
||||
// userRule = proxyInstance.proxyRule,
|
||||
webBasePath = 'web';
|
||||
const webBasePath = 'web';
|
||||
let ruleSummary = '';
|
||||
let customMenu = [];
|
||||
|
||||
try {
|
||||
ruleSummary = ''; //userRule.summary();
|
||||
customMenu = ''; // userRule._getCustomMenu();
|
||||
} catch (e) { }
|
||||
ruleSummary = ''; // userRule.summary();
|
||||
customMenu = []; // userRule._getCustomMenu();
|
||||
} catch (e) { LogUtil.error(e.stack); }
|
||||
|
||||
const myAbsAddress = 'http://' + ipAddress + ':' + self.webPort + '/',
|
||||
staticDir = path.join(__dirname, '../', webBasePath);
|
||||
const myAbsAddress = 'http://' + ipAddress + ':' + self.webPort + '/';
|
||||
const staticDir = path.join(__dirname, '../', webBasePath);
|
||||
|
||||
const app = express();
|
||||
app.use(compress()); //invoke gzip
|
||||
app.use(compress()); // invoke gzip
|
||||
app.use((req, res, next) => {
|
||||
res.setHeader('note', 'THIS IS A REQUEST FROM ANYPROXY WEB INTERFACE');
|
||||
return next();
|
||||
@ -97,7 +114,7 @@ class webInterface extends events.EventEmitter {
|
||||
res.json({});
|
||||
} else if (result.mime) {
|
||||
if (query.raw === 'true') {
|
||||
//TODO : cache query result
|
||||
// TODO : cache query result
|
||||
res.type(result.mime).end(result.content);
|
||||
} else if (query.download === 'true') {
|
||||
res.setHeader('Content-disposition', `attachment; filename=${result.fileName}`);
|
||||
@ -118,21 +135,21 @@ class webInterface extends events.EventEmitter {
|
||||
if (query && query.id) {
|
||||
recorder.getDecodedBody(parseInt(query.id, 10), (err, result) => {
|
||||
// 返回下载信息
|
||||
const _resDownload = function (isDownload) {
|
||||
const resDownload = function(isDownload: boolean): void {
|
||||
isDownload = typeof isDownload === 'boolean' ? isDownload : true;
|
||||
res.json({
|
||||
id: query.id,
|
||||
type: result.type,
|
||||
method: result.meethod,
|
||||
method: result.method,
|
||||
fileName: result.fileName,
|
||||
ref: `/downloadBody?id=${query.id}&download=${isDownload}&raw=${!isDownload}`
|
||||
ref: `/downloadBody?id=${query.id}&download=${isDownload}&raw=${!isDownload}`,
|
||||
});
|
||||
};
|
||||
|
||||
// 返回内容
|
||||
const _resContent = () => {
|
||||
if (util.getByteSize(result.content || '') > MAX_CONTENT_SIZE) {
|
||||
_resDownload(true);
|
||||
const resContent = () => {
|
||||
if (util.getByteSize(result.content || Buffer.from('')) > MAX_CONTENT_SIZE) {
|
||||
resDownload(true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -140,7 +157,7 @@ class webInterface extends events.EventEmitter {
|
||||
id: query.id,
|
||||
type: result.type,
|
||||
method: result.method,
|
||||
resBody: result.content
|
||||
resBody: result.content,
|
||||
});
|
||||
};
|
||||
|
||||
@ -151,14 +168,14 @@ class webInterface extends events.EventEmitter {
|
||||
result.mime.indexOf('text') === 0 ||
|
||||
// deal with 'application/x-javascript' and 'application/javascript'
|
||||
result.mime.indexOf('javascript') > -1) {
|
||||
_resContent();
|
||||
resContent();
|
||||
} else if (result.type === 'image') {
|
||||
_resDownload(false);
|
||||
resDownload(false);
|
||||
} else {
|
||||
_resDownload(true);
|
||||
resDownload(true);
|
||||
}
|
||||
} else {
|
||||
_resContent();
|
||||
resContent();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -203,49 +220,51 @@ class webInterface extends events.EventEmitter {
|
||||
|
||||
app.get('/fetchCrtFile', (req, res) => {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
const _crtFilePath = certMgr.getRootCAFilePath();
|
||||
if (_crtFilePath) {
|
||||
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 }));
|
||||
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
|
||||
// make qr code
|
||||
app.get('/qr', (req, res) => {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
const qr = qrCode.qrcode(4, 'M'),
|
||||
targetUrl = myAbsAddress;
|
||||
const qr = qrCode.qrcode(4, 'M');
|
||||
const 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);
|
||||
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';
|
||||
const qr = qrCode.qrcode(4, 'M');
|
||||
const 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);
|
||||
// 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();
|
||||
const isRootCAFileExists = certMgr.ifRootCAFileExists();
|
||||
res.json({
|
||||
status: 'success',
|
||||
url: targetUrl,
|
||||
isRootCAFileExists,
|
||||
qrImgDom: qrImageTag
|
||||
qrImgDom: qrImageTag,
|
||||
});
|
||||
});
|
||||
|
||||
@ -254,7 +273,7 @@ class webInterface extends events.EventEmitter {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
const rootCAExists = certMgr.isRootCAFileExists();
|
||||
const rootDirPath = certMgr.getRootDirPath();
|
||||
const interceptFlag = false; //proxyInstance.getInterceptFlag(); TODO
|
||||
const interceptFlag = false; // proxyInstance.getInterceptFlag(); TODO
|
||||
const globalProxyFlag = false; // TODO: proxyInstance.getGlobalProxyFlag();
|
||||
res.json({
|
||||
status: 'success',
|
||||
@ -264,8 +283,8 @@ class webInterface extends events.EventEmitter {
|
||||
currentGlobalProxyFlag: globalProxyFlag,
|
||||
ruleSummary: ruleSummary || '',
|
||||
ipAddress: util.getAllIpAddress(),
|
||||
port: '', //proxyInstance.proxyPort, // TODO
|
||||
appVersion: packageJson.version
|
||||
port: '', // proxyInstance.proxyPort, // TODO
|
||||
appVersion: packageJson.version,
|
||||
});
|
||||
});
|
||||
|
||||
@ -276,23 +295,23 @@ class webInterface extends events.EventEmitter {
|
||||
certMgr.generateRootCA(() => {
|
||||
res.json({
|
||||
status: 'success',
|
||||
code: 'done'
|
||||
code: 'done',
|
||||
});
|
||||
});
|
||||
} else {
|
||||
res.json({
|
||||
status: 'success',
|
||||
code: 'root_ca_exists'
|
||||
code: 'root_ca_exists',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.use((req, res, next) => {
|
||||
const indexTpl = fs.readFileSync(path.join(staticDir, '/index.html'), { encoding: 'utf8' }),
|
||||
opt = {
|
||||
const indexTpl = fs.readFileSync(path.join(staticDir, '/index.html'), { encoding: 'utf8' });
|
||||
const opt = {
|
||||
rule: ruleSummary || '',
|
||||
customMenu: customMenu || [],
|
||||
ipAddress: ipAddress || '127.0.0.1'
|
||||
ipAddress: ipAddress || '127.0.0.1',
|
||||
};
|
||||
|
||||
if (url.parse(req.url).pathname === '/') {
|
||||
@ -306,25 +325,25 @@ class webInterface extends events.EventEmitter {
|
||||
return app;
|
||||
}
|
||||
|
||||
start() {
|
||||
public start(): Promise<undefined> {
|
||||
const self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
self.server = self.app.listen(self.webPort);
|
||||
self.wsServer = new wsServer({
|
||||
server: self.server
|
||||
self.server = (self.app as any).listen(self.webPort);
|
||||
self.wsServer = new WsServer({
|
||||
server: self.server,
|
||||
}, self.recorder);
|
||||
self.wsServer.start();
|
||||
resolve();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
close() {
|
||||
public close(cb: (error: Error) => void): void {
|
||||
this.server && this.server.close();
|
||||
this.wsServer && this.wsServer.closeAll();
|
||||
this.server = null;
|
||||
this.wsServer = null;
|
||||
this.proxyInstance = null;
|
||||
// this.proxyInstance = null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = webInterface;
|
||||
export default WebInterface;
|
@ -1,10 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
// websocket server manager
|
||||
// websocket server manager, for the webinterface websocket handling
|
||||
import * as WebSocket from 'ws';
|
||||
import Recorder from './recorder';
|
||||
import logUtil from './log';
|
||||
import { Server } from 'http';
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
|
||||
declare interface IWsMessage {
|
||||
type?: 'error' | 'body';
|
||||
@ -18,7 +19,8 @@ declare interface IWsMessage {
|
||||
}
|
||||
|
||||
declare interface IWsServerConfig {
|
||||
server: Server;
|
||||
server: http.Server | https.Server;
|
||||
connHandler?: (wsClient: WebSocket, wsReq: http.IncomingMessage) => void;
|
||||
}
|
||||
|
||||
declare interface IMultiMessageQueue {
|
||||
@ -198,4 +200,4 @@ class WsServer {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WsServer;
|
||||
export default WsServer;
|
||||
|
@ -1,9 +1,10 @@
|
||||
/**
|
||||
* manage the websocket server
|
||||
* manage the websocket server, for proxy target only
|
||||
*
|
||||
*/
|
||||
import * as ws from 'ws';
|
||||
import * as http from 'http';
|
||||
import * as https from 'https';
|
||||
import logUtil from './log.js';
|
||||
|
||||
const WsServer = ws.Server;
|
||||
@ -15,7 +16,7 @@ const WsServer = ws.Server;
|
||||
{handler} config.handler
|
||||
*/
|
||||
function getWsServer(config: {
|
||||
server: http.Server;
|
||||
server: http.Server | https.Server;
|
||||
connHandler: (wsClient: ws, wsReq: http.IncomingMessage) => void;
|
||||
}): ws.Server {
|
||||
const wss = new WsServer({
|
||||
|
@ -40,6 +40,7 @@
|
||||
"ws": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.16.0",
|
||||
"@types/node": "^8.10.21",
|
||||
"@types/ws": "^6.0.0",
|
||||
"antd": "^2.5.0",
|
||||
|
@ -14,6 +14,8 @@
|
||||
"only-arrow-functions": false,
|
||||
"no-reference": false,
|
||||
"forin": false,
|
||||
"member-ordering": false,
|
||||
"max-classes-per-file": false,
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature",
|
||||
|
29
typings/index.d.ts
vendored
29
typings/index.d.ts
vendored
@ -7,17 +7,27 @@ declare module NodeJS {
|
||||
}
|
||||
}
|
||||
|
||||
declare interface AnyProxyWebInterfaceConfig {
|
||||
webPort?: number;
|
||||
}
|
||||
|
||||
declare interface AnyProxyConfig {
|
||||
port: string; // 代理监听端口
|
||||
httpServerPort: string; // web server 的端口
|
||||
forceProxyHttps: boolean;
|
||||
dangerouslyIgnoreUnauthorized: boolean; // 是否忽略https证书
|
||||
wsIntercept: boolean; // 是否代理websocket
|
||||
chunkSizeThreshold: number; // throttle的配置
|
||||
port?: string; // port of the proxy server
|
||||
httpServerPort?: string; // web server 的端口
|
||||
type?: 'http' | 'https'; // type of the proxy server
|
||||
forceProxyHttps?: boolean; // proxy https also
|
||||
dangerouslyIgnoreUnauthorized?: boolean; // should ignore
|
||||
wsIntercept?: boolean; // should proxy websocket
|
||||
throttle?: string; // speed limit in kb/s
|
||||
hostname?: string; // the hostname of this proxy, default to 'localhost'
|
||||
recorder?: any; // A Recorder instance
|
||||
silent?: boolean; // if keep the console silent
|
||||
rule?: any; // rule module to use
|
||||
webInterface?: AnyProxyWebInterfaceConfig;
|
||||
}
|
||||
|
||||
declare interface AnyProxyRule {
|
||||
summary?: string,
|
||||
summary?: string | Function,
|
||||
beforeSendRequest?: Function,
|
||||
beforeSendResponse?: Function,
|
||||
beforeDealHttpsRequest?: Function,
|
||||
@ -87,3 +97,8 @@ declare interface IExecScriptResult {
|
||||
status: number;
|
||||
stdout?: string;
|
||||
}
|
||||
|
||||
declare module "*.json" {
|
||||
const value: any;
|
||||
export default value;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user