代码拉取完成,页面将自动刷新
var http = require('http');
var net = require('net');
var url = require('url');
let https = require('https');
let fs = require('fs');
let os = require('os');
let ws = require('ws');
let zlib = require('zlib');
let {exec: asyncExec} = require('child_process');
let G = {};
function getLocalIp() {
let interfaces = os.networkInterfaces();
for(let name in interfaces) {
for(let info of interfaces[name]) {
if(info.family == 'IPv4' && info.address != '127.0.0.1' && !info.internal) {
return info.address;
}
}
}
}
function exec(command, options = {}, log = false) {
if(Array.isArray(command)) {
command = command.join(' ');
}
log && fs.appendFileSync('command.txt',command+os.EOL);
return new Promise((rs, rj)=>{
asyncExec(command, options, (err, sto, ste)=>{
if(err) {
rj(err);
} else {
rs(ste || sto);
}
});
});
}
function fExists(path) {
try {
fs.accessSync(path, fs.constants.F_OK);
return true;
} catch(e) {
return false;
}
}
function sleep(intval) {
return new Promise((rs,rj)=>{
setTimeout(()=>{rs()},intval);
});
}
function isIPHost(host) {
return /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(:\d+)*$/.test(host);
}
function getBaseHost(host) {
let baseHost;
if(isIPHost(host)) {
baseHost = host.split(':')[0];
} else {
let arr = host.split(':')[0].split('.');
if(arr.length > 2) {
arr.shift()
}
baseHost = arr.join('.');
}
return baseHost;
}
function getHostConfigFile(baseHost) {
let cfg = ['',
'[alt_ext]',
`subjectAltName = @alt_names`,
'',
'[alt_names]',
];
if(isIPHost(baseHost)) {
cfg.push(`IP.1 = ${baseHost}`);
} else {
cfg.push(`DNS.1 = ${baseHost}`,`DNS.2 = *.${baseHost}`);
}
let extCfg = Buffer.from(cfg.join(os.EOL));
let cfgPath = `${G.certDir}/${baseHost}.cfg`;
fs.writeFileSync(cfgPath, Buffer.concat([G.certConfig,extCfg]));
return cfgPath;
}
function getCAConfigFile() {
let cfgPath = `${G.certDir}/ca.cfg`;
if(!fExists(cfgPath)) {
let cfg = ['',
'[ext]',
`basicConstraints=CA:TRUE`,
];
let extCfg = Buffer.from(cfg.join(os.EOL));
fs.writeFileSync(cfgPath, Buffer.concat([G.certConfig,extCfg]));
}
return cfgPath;
}
async function generateCA() {
let dir = G.certDir;
if(fExists(`${dir}/ca.crt`) && fExists(`${dir}/ca.key`)) {
return;
}
let config = getCAConfigFile();
await exec(`openssl genrsa -out ca.key 2048`,{cwd:dir});
await exec(['openssl','req',`-config ${config} -extensions ext`,'-subj',
`"/C=CN/ST=SH/L=SH/O=Gin/OU=Gin/CN=Gin CA/emailAddress=gin@gin.com"`,
'-new','-x509','-days','3650','-key','ca.key','-out','ca.crt'],{cwd:dir});
}
async function init() {
G.servers = {};
G.wsServers = {};
G.delimiter = '|`|&|$|#|';
G.transId = 0;
G.localIp = getLocalIp();
G.certDir = `${__dirname}/certificateCache`;
if(!fExists(G.certDir)) {
fs.mkdirSync(G.certDir);
}
let opensslDirInfo = await exec('openssl version -d');
let opensslDir = opensslDirInfo.match(/"([a-z\/ ]+)"/)[1];
G.certConfig = fs.readFileSync(`${opensslDir}/openssl.cnf`);
await generateCA();
if(!fExists(`${G.certDir}/server.key`)) {
await exec(`openssl genrsa -out server.key 2048`,{cwd:G.certDir});
}
G.certGenerator = (() => {
let lockList = {};
return async function generate(baseHost) {
while(true) {
if(baseHost in lockList) {
await sleep(0);
} else {
break;
}
}
lockList[baseHost] = true;
let dir = G.certDir;
let hostCsr = `${baseHost}.csr`;
let hostCrt = `${baseHost}.crt`;
let keyPath = `${dir}/server.key`;
let crtPath = `${dir}/${hostCrt}`;
if(fExists(crtPath)) {
delete lockList[baseHost];
return {key: keyPath, crt: crtPath};
}
let cfgPath = getHostConfigFile(baseHost);
await exec(['openssl','req','-subj',
`"/C=CN/ST=SH/L=SH/O=Gin/OU=Gin/CN=${isIPHost(baseHost)?'':'*.'}${baseHost}/emailAddress=test@${baseHost}"`,
'-reqexts alt_ext',`-config ${cfgPath}`,'-sha256',
'-new','-key',keyPath,'-out',hostCsr],{cwd:dir});
await exec(['openssl','x509','-req','-days','3650','-in',hostCsr,
'-extensions alt_ext',`-extfile ${cfgPath}`,'-sha256',
'-CA','ca.crt','-CAkey','ca.key','-set_serial','01','-out',hostCrt],{cwd:dir});
delete lockList[baseHost];
return {key: keyPath, crt: crtPath};
}
})();
}
function request(cReq, cRes) {
var u = url.parse(cReq.url);
let host = u.hostname, port = u.port || 80;
if(u.hostname == 'https-proxy.gin') {
host = 'localhost';
port = 5229;
}
var options = {
hostname : host,
port : port,
path : u.path,
method : cReq.method,
headers : cReq.headers
};
var pReq = http.request(options, function(pRes) {
cRes.writeHead(pRes.statusCode, pRes.headers);
pRes.pipe(cRes);
}).on('error', function(e) {
cRes.end();
});
cReq.pipe(pReq);
}
async function connect(originalReq, originalSock) {
let server = await createHttpsServer(originalReq.headers.host, reqHandler, wsHandler);
let params = [];
if(server) {
params.push(server.port);
} else {
params.push(443, originalReq.headers.host)
}
let proxySock = net.connect(...params, function() {
originalSock.write('HTTP/1.1 200 Connection Established\r\n\r\n');
proxySock.pipe(originalSock);
}).on('error', function(e) {
originalSock.end();
});
originalSock.pipe(proxySock);
}
function wsHandler(server){
let queue = [];
let wss = new ws.Server({server});
wss.on('connection', (socket, req)=>{
let protocol = (req.connection && req.connection.encrypted) ? 'wss' : 'ws';
let proxyWs = new ws(`${protocol}://${req.headers.host}${req.url}`,{
headers : filterHeader(req.headers),
});
proxyWs.on('open',()=>{
send();
});
proxyWs.on('message',(data)=>{
socket.send(data);
});
socket.on('message',(data)=>{
let transId = G.transId++;
mWsSend('req',transId,`wss://${req.headers.host}${req.url}`,data.toString());
send(data);
});
function send(data) {
data && queue.push(data);
if(proxyWs.readyState === 1) {
while(queue.length) {
proxyWs.send(queue.shift());
}
}
}
function filterHeader(headers) {
let originHeaders = Object.assign({}, headers);
Object.keys(originHeaders).forEach((key) => {
if (/sec-websocket/ig.test(key)) {
delete originHeaders[key];
}
});
delete originHeaders.connection;
delete originHeaders.upgrade;
return originHeaders;
}
});
wss.on('headers', (headers, req)=>{
});
wss.on('close', (data)=>{
});
wss.on('error',(error)=>{
});
return wss;
}
function reqHandler(proxyReq, proxyRes){
let transId = G.transId++;
let [host, port = 443] = proxyReq.headers.host.split(':');
let headers = Object.assign({},proxyReq.headers);
for(let key in headers) {
if(key.toLowerCase() == 'accept-encoding') {
headers[key] = 'gzip, deflate';
break;
}
}
let options = {
hostname : host,
port : port,
path : proxyReq.url,
method : proxyReq.method,
headers : headers,
rejectUnauthorized : false,
};
let proxyData = [];
proxyReq.on('data',function(d){
proxyData.push(d);
});
proxyReq.on('end',async function(){
let realReq = https.request(options, function(realRes){
let realData = [];
realRes.on('data',function(d){
realData.push(d);
});
realRes.on('end',function(){
proxyRes.writeHead(realRes.statusCode, realRes.headers);
realData = Buffer.concat(realData);
let showData = realData;
switch(realRes.headers['content-encoding']) {
case 'gzip':
showData = zlib.gunzipSync(realData);
break;
case 'deflate':
showData = zlib.inflateSync(realData);
break;
default:
}
mWsSend('res',transId,``,showData.toString());
proxyRes.end(realData);
});
});
realReq.on('error',function(e){
});
proxyData = Buffer.concat(proxyData);
mWsSend('req',transId,`https://${proxyReq.headers.host}${proxyReq.url}`,proxyData.toString());
realReq.end(proxyData);
});
}
async function createHttpsServer(host, reqHandler, wsHandler) {
let baseHost = getBaseHost(host);
if(!(baseHost in G.servers)) {
let cert = await G.certGenerator(baseHost);
G.servers[baseHost] = await new Promise((rs, rj)=>{
const options = {
key: fs.readFileSync(cert.key),
cert: fs.readFileSync(cert.crt)
};
let server = https.createServer(options, reqHandler).listen(0, function() {
rs({port:server.address().port, server});
});
server.on('upgrade',()=>{
if(!(baseHost in G.wsServers)) {
G.wsServers[baseHost] = wsHandler(server);
}
});
});
}
return G.servers[baseHost];
}
function releaseServer(baseHost) {
if(baseHost in G.servers) {
G.servers[baseHost].server.close(()=>{
delete G.servers[baseHost];
});
}
}
let monitorSockets = [];
function mWsSend() {
let data = [...arguments].join(G.delimiter);
monitorSockets.forEach((socket)=>{
socket.send(data);
});
}
(async ()=>{
await init();
let server = http.createServer();
server.on('request', request);
server.on('connect', connect);
server.listen(5227, G.localIp, ()=>{
console.log('proxy server is running on prot 5227');
let monitorSever = http.createServer(function(req, res){
if(req.url === '/favicon.ico') {
res.end('');
}
if(req.url === '/crt') {
res.setHeader('Content-disposition', 'attachment; filename=ca.crt');
fs.createReadStream(`${G.certDir}/ca.crt`).pipe(res);
}
if(req.url === '/') {
res.setHeader('Content-type', 'text/html; charset=utf8');
res.end(fs.readFileSync('./proxy.html').toString()
.replace(/__localIp__/gm,G.localIp));
}
}).listen(5229,()=>{
console.log('monitor url is http://https-proxy.gin');
});
let monitorWs = new ws.Server({server:monitorSever});
monitorWs.on('connection', function(socket){
socket.send(`delimiter:${G.delimiter}`);
monitorSockets.push(socket);
});
});
})();
async function testCert(host) {
let cert = await G.certGenerator(host);
const options = {
key: fs.readFileSync(cert.key),
cert: fs.readFileSync(cert.crt)
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end(`this is not real ${host}`);
}).listen(5230,()=>{
console.log(`before visit 'https://${host}:5230',
don't forget add '${host} 127.0.0.1' to the hosts file`);
});
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。