Skip to content

Commit

Permalink
First test
Browse files Browse the repository at this point in the history
  • Loading branch information
Xzandro committed Feb 11, 2024
1 parent 6d519dd commit 47dc6c5
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 11 deletions.
20 changes: 20 additions & 0 deletions app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const { object, string, number, date } = require('yup');
const { parse } = require('yaml');
const { validate, compare } = require('compare-versions');
const SWProxy = require('./proxy/SWProxy');
const transparentProxy = require('./steamproxy/transparent_proxy');

const path = require('path');
const url = require('url');
Expand Down Expand Up @@ -390,6 +391,25 @@ app.on('ready', async () => {
app.setAppUserModelId(process.execPath);
createWindow();

if (process.platform == 'win32') {
const proxyHost = '127.0.0.1';
const proxyPort = 8099;
const proxiedHostnames = {
'summonerswar-eu-lb.qpyou.cn': '127.11.12.13',
'summonerswar-gb-lb.qpyou.cn': '127.11.12.14',
'summonerswar-sea-lb.qpyou.cn': '127.11.12.15',
'summonerswar-jp-lb.qpyou.cn': '127.11.12.16',
'summonerswar-kr-lb.qpyou.cn': '127.11.12.17',
'summonerswar-cn-lb.qpyou.cn': '127.11.12.18',
};

for (const hostname in proxiedHostnames) {
const proxy = new transparentProxy.TransparentProxy(hostname, 443, proxyHost, proxyPort);
const bindAddr = proxiedHostnames[hostname];
proxy.run(bindAddr, 443);
}
}

if (process.platform === 'darwin') {
// Create our menu entries so that we can use MAC shortcuts like copy & paste
Menu.setApplicationMenu(
Expand Down
40 changes: 29 additions & 11 deletions app/proxy/SWProxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const fs = require('fs-extra');
const path = require('path');
const os = require('os');
const net = require('net');
const https = require('https');
const dns = require('dns');
const url = require('url');
const uuidv4 = require('uuid/v4');
const Proxy = require('http-mitm-proxy');
Expand Down Expand Up @@ -159,18 +161,34 @@ class SWProxy extends EventEmitter {
socket.on('error', () => {});
}
});
this.proxy.listen({ host: '::', port, sslCaDir: path.join(app.getPath('userData'), 'swcerts') }, async (e) => {
this.log({ type: 'info', source: 'proxy', message: `Now listening on port ${port}` });
const expired = await this.checkCertExpiration();

if (expired) {
this.log({
type: 'warning',
source: 'proxy',
message: `Your certificate is older than ${CERT_MAX_LIFETIME_IN_MONTHS} months. If you experience connection issues, please regenerate a new one via the Settings.`,
});
const dnsResolver = new dns.Resolver();
this.proxy.listen(
{
host: '::',
port,
sslCaDir: path.join(app.getPath('userData'), 'swcerts'),
httpsAgent: new https.Agent({
keepAlive: false,
lookup: (hostname, options, callback) => {
dnsResolver.resolve4(hostname, (err, result) => {
callback(err, result[0], 4);
});
},
}),
},
async (e) => {
this.log({ type: 'info', source: 'proxy', message: `Now listening on port ${port}` });
const expired = await this.checkCertExpiration();

if (expired) {
this.log({
type: 'warning',
source: 'proxy',
message: `Your certificate is older than ${CERT_MAX_LIFETIME_IN_MONTHS} months. If you experience connection issues, please regenerate a new one via the Settings.`,
});
}
}
});
);

if (process.env.autostart) {
console.log(`SW Exporter Proxy is listening on port ${port}`);
Expand Down
35 changes: 35 additions & 0 deletions app/steamproxy/sock_util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict';

const net = require('net');

/**
*
* @param {net.Socket} socket
* @param {String} separator
*/
function readUntil(socket, separator) {
// This is definitely not the best implementation,
// you can make it more efficient if you have nothing better to do
return new Promise((resolve, reject) => {
const result = [];
function readUntilInner() {
let data = socket.read(1);
while (data !== null) {
result.push(data);
if (data.toString() === separator) {
resolve(Buffer.concat(result).toString());
return;
}
data = socket.read(1);
}
if (socket.destroyed) {
reject("Can't read line: connection closed");
return;
}
setTimeout(readUntilInner, 5);
}
readUntilInner();
});
}

module.exports = { readUntil: readUntil };
69 changes: 69 additions & 0 deletions app/steamproxy/transparent_proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use strict';

const net = require('net');
const sockUtil = require('./sock_util');

class TransparentProxy {
constructor(proxiedHostname, proxiedPort, proxyHost, proxyPort) {
this.proxiedHostname = proxiedHostname;
this.proxiedPort = proxiedPort;
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
this.server = net.createServer((connection) => {
this.onConnect(connection);
});
}

/**
*
* @param {net.Socket} connection
*/
async onConnect(connection) {
const upstreamConnection = net.connect(this.proxyPort, this.proxyHost, () => {
this.httpProxyConnect(connection, upstreamConnection);
});
const onSocketError = (err) => {
console.error(`Socket error: ${err}`);
connection.destroy();
upstreamConnection.destroy();
};
const onSocketClose = () => {
connection.destroy();
upstreamConnection.destroy();
};
connection.on('error', onSocketError);
upstreamConnection.on('error', onSocketError);
connection.on('close', onSocketClose);
upstreamConnection.on('close', onSocketClose);
// Add timeout?
}

/**
*
* @param {net.Socket} downstream
* @param {net.Socket} upstream
*/
async httpProxyConnect(downstream, upstream) {
try {
// Add keep-alive header?
upstream.write(`CONNECT ${this.proxiedHostname}:${this.proxiedPort} HTTP/0.9\r\n\r\n`);
const statusLine = await sockUtil.readUntil(upstream, '\n');
const statusCode = Number.parseInt(statusLine.split(' ')[1]);
if (statusCode < 200 || statusCode > 299) {
throw Error(`Server returned non-200 status code: ${statusCode}`);
}
while ((await sockUtil.readUntil(upstream, '\n')).trim().length !== 0) {} // read headers
downstream.pipe(upstream);
upstream.pipe(downstream);
} catch (error) {
console.error(`Error while connecting to http proxy: ${error}`);
upstream.destroy(); // downstream is destroyed in onSocketClose function
}
}

run(hostname, port) {
this.server.listen(port, hostname);
}
}

module.exports = { TransparentProxy: TransparentProxy };

0 comments on commit 47dc6c5

Please sign in to comment.