@push.rocks/smartproxy 3.10.4 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.iptablesproxy.d.ts +23 -0
- package/dist_ts/classes.iptablesproxy.js +78 -0
- package/dist_ts/classes.networkproxy.d.ts +31 -0
- package/dist_ts/classes.networkproxy.js +305 -0
- package/dist_ts/classes.port80handler.d.ts +37 -0
- package/dist_ts/classes.port80handler.js +186 -0
- package/dist_ts/classes.portproxy.d.ts +26 -0
- package/dist_ts/classes.portproxy.js +295 -0
- package/dist_ts/classes.router.d.ts +13 -0
- package/dist_ts/classes.router.js +33 -0
- package/dist_ts/classes.sslredirect.d.ts +8 -0
- package/dist_ts/classes.sslredirect.js +28 -0
- package/dist_ts/helpers.certificates.d.ts +5 -0
- package/dist_ts/helpers.certificates.js +23 -0
- package/dist_ts/index.d.ts +5 -3
- package/dist_ts/index.js +6 -4
- package/package.json +2 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.iptablesproxy.ts +88 -0
- package/ts/{smartproxy.classes.networkproxy.ts → classes.networkproxy.ts} +1 -1
- package/ts/classes.port80handler.ts +214 -0
- package/ts/{smartproxy.portproxy.ts → classes.portproxy.ts} +3 -3
- package/ts/index.ts +5 -3
- /package/ts/{smartproxy.classes.router.ts → classes.router.ts} +0 -0
- /package/ts/{smartproxy.classes.sslredirect.ts → classes.sslredirect.ts} +0 -0
- /package/ts/{smartproxy.helpers.certificates.ts → helpers.certificates.ts} +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartproxy',
|
|
6
|
-
version: '3.
|
|
6
|
+
version: '3.12.0',
|
|
7
7
|
description: 'a proxy for handling high workloads of proxying'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFFBQVE7SUFDakIsV0FBVyxFQUFFLGlEQUFpRDtDQUMvRCxDQUFBIn0=
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface IIpTableProxySettings {
|
|
2
|
+
fromPort: number;
|
|
3
|
+
toPort: number;
|
|
4
|
+
toHost?: string;
|
|
5
|
+
preserveSourceIP?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* IPTablesProxy sets up iptables NAT rules to forward TCP traffic.
|
|
9
|
+
* It only supports basic port forwarding.
|
|
10
|
+
*/
|
|
11
|
+
export declare class IPTablesProxy {
|
|
12
|
+
settings: IIpTableProxySettings;
|
|
13
|
+
private rulesInstalled;
|
|
14
|
+
constructor(settings: IIpTableProxySettings);
|
|
15
|
+
/**
|
|
16
|
+
* Sets up iptables rules for port forwarding.
|
|
17
|
+
*/
|
|
18
|
+
start(): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Removes the iptables rules that were added in start().
|
|
21
|
+
*/
|
|
22
|
+
stop(): Promise<void>;
|
|
23
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
const execAsync = promisify(exec);
|
|
4
|
+
/**
|
|
5
|
+
* IPTablesProxy sets up iptables NAT rules to forward TCP traffic.
|
|
6
|
+
* It only supports basic port forwarding.
|
|
7
|
+
*/
|
|
8
|
+
export class IPTablesProxy {
|
|
9
|
+
constructor(settings) {
|
|
10
|
+
this.rulesInstalled = false;
|
|
11
|
+
this.settings = {
|
|
12
|
+
...settings,
|
|
13
|
+
toHost: settings.toHost || 'localhost',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Sets up iptables rules for port forwarding.
|
|
18
|
+
*/
|
|
19
|
+
async start() {
|
|
20
|
+
const dnatCmd = `iptables -t nat -A PREROUTING -p tcp --dport ${this.settings.fromPort} -j DNAT --to-destination ${this.settings.toHost}:${this.settings.toPort}`;
|
|
21
|
+
try {
|
|
22
|
+
await execAsync(dnatCmd);
|
|
23
|
+
console.log(`Added iptables rule: ${dnatCmd}`);
|
|
24
|
+
this.rulesInstalled = true;
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
console.error(`Failed to add iptables DNAT rule: ${err}`);
|
|
28
|
+
throw err;
|
|
29
|
+
}
|
|
30
|
+
if (!this.settings.preserveSourceIP) {
|
|
31
|
+
const masqueradeCmd = `iptables -t nat -A POSTROUTING -p tcp -d ${this.settings.toHost} --dport ${this.settings.toPort} -j MASQUERADE`;
|
|
32
|
+
try {
|
|
33
|
+
await execAsync(masqueradeCmd);
|
|
34
|
+
console.log(`Added iptables rule: ${masqueradeCmd}`);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
console.error(`Failed to add iptables MASQUERADE rule: ${err}`);
|
|
38
|
+
// Roll back the DNAT rule if MASQUERADE fails.
|
|
39
|
+
try {
|
|
40
|
+
const rollbackCmd = `iptables -t nat -D PREROUTING -p tcp --dport ${this.settings.fromPort} -j DNAT --to-destination ${this.settings.toHost}:${this.settings.toPort}`;
|
|
41
|
+
await execAsync(rollbackCmd);
|
|
42
|
+
this.rulesInstalled = false;
|
|
43
|
+
}
|
|
44
|
+
catch (rollbackErr) {
|
|
45
|
+
console.error(`Rollback failed: ${rollbackErr}`);
|
|
46
|
+
}
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Removes the iptables rules that were added in start().
|
|
53
|
+
*/
|
|
54
|
+
async stop() {
|
|
55
|
+
if (!this.rulesInstalled)
|
|
56
|
+
return;
|
|
57
|
+
const dnatDelCmd = `iptables -t nat -D PREROUTING -p tcp --dport ${this.settings.fromPort} -j DNAT --to-destination ${this.settings.toHost}:${this.settings.toPort}`;
|
|
58
|
+
try {
|
|
59
|
+
await execAsync(dnatDelCmd);
|
|
60
|
+
console.log(`Removed iptables rule: ${dnatDelCmd}`);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
console.error(`Failed to remove iptables DNAT rule: ${err}`);
|
|
64
|
+
}
|
|
65
|
+
if (!this.settings.preserveSourceIP) {
|
|
66
|
+
const masqueradeDelCmd = `iptables -t nat -D POSTROUTING -p tcp -d ${this.settings.toHost} --dport ${this.settings.toPort} -j MASQUERADE`;
|
|
67
|
+
try {
|
|
68
|
+
await execAsync(masqueradeDelCmd);
|
|
69
|
+
console.log(`Removed iptables rule: ${masqueradeDelCmd}`);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
console.error(`Failed to remove iptables MASQUERADE rule: ${err}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
this.rulesInstalled = false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5pcHRhYmxlc3Byb3h5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5pcHRhYmxlc3Byb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDckMsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVqQyxNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7QUFTbEM7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLGFBQWE7SUFJeEIsWUFBWSxRQUErQjtRQUZuQyxtQkFBYyxHQUFZLEtBQUssQ0FBQztRQUd0QyxJQUFJLENBQUMsUUFBUSxHQUFHO1lBQ2QsR0FBRyxRQUFRO1lBQ1gsTUFBTSxFQUFFLFFBQVEsQ0FBQyxNQUFNLElBQUksV0FBVztTQUN2QyxDQUFDO0lBQ0osQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLEtBQUs7UUFDaEIsTUFBTSxPQUFPLEdBQUcsZ0RBQWdELElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSw2QkFBNkIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNsSyxJQUFJLENBQUM7WUFDSCxNQUFNLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUN6QixPQUFPLENBQUMsR0FBRyxDQUFDLHdCQUF3QixPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQy9DLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDO1FBQzdCLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsT0FBTyxDQUFDLEtBQUssQ0FBQyxxQ0FBcUMsR0FBRyxFQUFFLENBQUMsQ0FBQztZQUMxRCxNQUFNLEdBQUcsQ0FBQztRQUNaLENBQUM7UUFFRCxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ3BDLE1BQU0sYUFBYSxHQUFHLDRDQUE0QyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sWUFBWSxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sZ0JBQWdCLENBQUM7WUFDdkksSUFBSSxDQUFDO2dCQUNILE1BQU0sU0FBUyxDQUFDLGFBQWEsQ0FBQyxDQUFDO2dCQUMvQixPQUFPLENBQUMsR0FBRyxDQUFDLHdCQUF3QixhQUFhLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELENBQUM7WUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO2dCQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkNBQTJDLEdBQUcsRUFBRSxDQUFDLENBQUM7Z0JBQ2hFLCtDQUErQztnQkFDL0MsSUFBSSxDQUFDO29CQUNILE1BQU0sV0FBVyxHQUFHLGdEQUFnRCxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsNkJBQTZCLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ3RLLE1BQU0sU0FBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDO29CQUM3QixJQUFJLENBQUMsY0FBYyxHQUFHLEtBQUssQ0FBQztnQkFDOUIsQ0FBQztnQkFBQyxPQUFPLFdBQVcsRUFBRSxDQUFDO29CQUNyQixPQUFPLENBQUMsS0FBSyxDQUFDLG9CQUFvQixXQUFXLEVBQUUsQ0FBQyxDQUFDO2dCQUNuRCxDQUFDO2dCQUNELE1BQU0sR0FBRyxDQUFDO1lBQ1osQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsSUFBSTtRQUNmLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYztZQUFFLE9BQU87UUFFakMsTUFBTSxVQUFVLEdBQUcsZ0RBQWdELElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSw2QkFBNkIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNySyxJQUFJLENBQUM7WUFDSCxNQUFNLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUM1QixPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixVQUFVLEVBQUUsQ0FBQyxDQUFDO1FBQ3RELENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsT0FBTyxDQUFDLEtBQUssQ0FBQyx3Q0FBd0MsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUMvRCxDQUFDO1FBRUQsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUNwQyxNQUFNLGdCQUFnQixHQUFHLDRDQUE0QyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sWUFBWSxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sZ0JBQWdCLENBQUM7WUFDMUksSUFBSSxDQUFDO2dCQUNILE1BQU0sU0FBUyxDQUFDLGdCQUFnQixDQUFDLENBQUM7Z0JBQ2xDLE9BQU8sQ0FBQyxHQUFHLENBQUMsMEJBQTBCLGdCQUFnQixFQUFFLENBQUMsQ0FBQztZQUM1RCxDQUFDO1lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztnQkFDYixPQUFPLENBQUMsS0FBSyxDQUFDLDhDQUE4QyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQ3JFLENBQUM7UUFDSCxDQUFDO1FBRUQsSUFBSSxDQUFDLGNBQWMsR0FBRyxLQUFLLENBQUM7SUFDOUIsQ0FBQztDQUNGIn0=
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { ProxyRouter } from './classes.router.js';
|
|
3
|
+
export interface INetworkProxyOptions {
|
|
4
|
+
port: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class NetworkProxy {
|
|
7
|
+
options: INetworkProxyOptions;
|
|
8
|
+
proxyConfigs: plugins.tsclass.network.IReverseProxyConfig[];
|
|
9
|
+
httpsServer: plugins.https.Server;
|
|
10
|
+
router: ProxyRouter;
|
|
11
|
+
socketMap: plugins.lik.ObjectMap<plugins.net.Socket>;
|
|
12
|
+
defaultHeaders: {
|
|
13
|
+
[key: string]: string;
|
|
14
|
+
};
|
|
15
|
+
heartbeatInterval: NodeJS.Timeout;
|
|
16
|
+
private defaultCertificates;
|
|
17
|
+
alreadyAddedReverseConfigs: {
|
|
18
|
+
[hostName: string]: plugins.tsclass.network.IReverseProxyConfig;
|
|
19
|
+
};
|
|
20
|
+
constructor(optionsArg: INetworkProxyOptions);
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Internal async handler for processing HTTP/HTTPS requests.
|
|
24
|
+
*/
|
|
25
|
+
private handleRequest;
|
|
26
|
+
updateProxyConfigs(proxyConfigsArg: plugins.tsclass.network.IReverseProxyConfig[]): Promise<void>;
|
|
27
|
+
addDefaultHeaders(headersArg: {
|
|
28
|
+
[key: string]: string;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
stop(): Promise<void>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { ProxyRouter } from './classes.router.js';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
export class NetworkProxy {
|
|
7
|
+
constructor(optionsArg) {
|
|
8
|
+
this.proxyConfigs = [];
|
|
9
|
+
this.router = new ProxyRouter();
|
|
10
|
+
this.socketMap = new plugins.lik.ObjectMap();
|
|
11
|
+
this.defaultHeaders = {};
|
|
12
|
+
this.alreadyAddedReverseConfigs = {};
|
|
13
|
+
this.options = optionsArg;
|
|
14
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const certPath = path.join(__dirname, '..', 'assets', 'certs');
|
|
16
|
+
try {
|
|
17
|
+
this.defaultCertificates = {
|
|
18
|
+
key: fs.readFileSync(path.join(certPath, 'key.pem'), 'utf8'),
|
|
19
|
+
cert: fs.readFileSync(path.join(certPath, 'cert.pem'), 'utf8')
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.error('Error loading certificates:', error);
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async start() {
|
|
28
|
+
// Instead of marking the callback async (which Node won't await),
|
|
29
|
+
// we call our async handler and catch errors.
|
|
30
|
+
this.httpsServer = plugins.https.createServer({
|
|
31
|
+
key: this.defaultCertificates.key,
|
|
32
|
+
cert: this.defaultCertificates.cert
|
|
33
|
+
}, (originRequest, originResponse) => {
|
|
34
|
+
this.handleRequest(originRequest, originResponse).catch((error) => {
|
|
35
|
+
console.error('Unhandled error in request handler:', error);
|
|
36
|
+
try {
|
|
37
|
+
originResponse.end();
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
// ignore errors during cleanup
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
// Enable websockets
|
|
45
|
+
const wsServer = new plugins.ws.WebSocketServer({ server: this.httpsServer });
|
|
46
|
+
// Set up the heartbeat interval
|
|
47
|
+
this.heartbeatInterval = setInterval(() => {
|
|
48
|
+
wsServer.clients.forEach((ws) => {
|
|
49
|
+
const wsIncoming = ws;
|
|
50
|
+
if (!wsIncoming.lastPong) {
|
|
51
|
+
wsIncoming.lastPong = Date.now();
|
|
52
|
+
}
|
|
53
|
+
if (Date.now() - wsIncoming.lastPong > 5 * 60 * 1000) {
|
|
54
|
+
console.log('Terminating websocket due to missing pong for 5 minutes.');
|
|
55
|
+
wsIncoming.terminate();
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
wsIncoming.ping();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}, 60000); // runs every 1 minute
|
|
62
|
+
wsServer.on('connection', (wsIncoming, reqArg) => {
|
|
63
|
+
console.log(`wss proxy: got connection for wsc for https://${reqArg.headers.host}${reqArg.url}`);
|
|
64
|
+
wsIncoming.lastPong = Date.now();
|
|
65
|
+
wsIncoming.on('pong', () => {
|
|
66
|
+
wsIncoming.lastPong = Date.now();
|
|
67
|
+
});
|
|
68
|
+
let wsOutgoing;
|
|
69
|
+
const outGoingDeferred = plugins.smartpromise.defer();
|
|
70
|
+
// --- Improvement 2: Only call routeReq once ---
|
|
71
|
+
const wsDestinationConfig = this.router.routeReq(reqArg);
|
|
72
|
+
if (!wsDestinationConfig) {
|
|
73
|
+
wsIncoming.terminate();
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
wsOutgoing = new plugins.wsDefault(`ws://${wsDestinationConfig.destinationIp}:${wsDestinationConfig.destinationPort}${reqArg.url}`);
|
|
78
|
+
console.log('wss proxy: initiated outgoing proxy');
|
|
79
|
+
wsOutgoing.on('open', async () => {
|
|
80
|
+
outGoingDeferred.resolve();
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
console.error('Error initiating outgoing WebSocket:', err);
|
|
85
|
+
wsIncoming.terminate();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
wsIncoming.on('message', async (message, isBinary) => {
|
|
89
|
+
try {
|
|
90
|
+
await outGoingDeferred.promise;
|
|
91
|
+
wsOutgoing.send(message, { binary: isBinary });
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error('Error sending message to wsOutgoing:', error);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
wsOutgoing.on('message', async (message, isBinary) => {
|
|
98
|
+
try {
|
|
99
|
+
wsIncoming.send(message, { binary: isBinary });
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
console.error('Error sending message to wsIncoming:', error);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
const terminateWsOutgoing = () => {
|
|
106
|
+
if (wsOutgoing) {
|
|
107
|
+
wsOutgoing.terminate();
|
|
108
|
+
console.log('Terminated outgoing ws.');
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
wsIncoming.on('error', terminateWsOutgoing);
|
|
112
|
+
wsIncoming.on('close', terminateWsOutgoing);
|
|
113
|
+
const terminateWsIncoming = () => {
|
|
114
|
+
if (wsIncoming) {
|
|
115
|
+
wsIncoming.terminate();
|
|
116
|
+
console.log('Terminated incoming ws.');
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
wsOutgoing.on('error', terminateWsIncoming);
|
|
120
|
+
wsOutgoing.on('close', terminateWsIncoming);
|
|
121
|
+
});
|
|
122
|
+
this.httpsServer.keepAliveTimeout = 600 * 1000;
|
|
123
|
+
this.httpsServer.headersTimeout = 600 * 1000;
|
|
124
|
+
this.httpsServer.on('connection', (connection) => {
|
|
125
|
+
this.socketMap.add(connection);
|
|
126
|
+
console.log(`Added connection. Now ${this.socketMap.getArray().length} sockets connected.`);
|
|
127
|
+
const cleanupConnection = () => {
|
|
128
|
+
if (this.socketMap.checkForObject(connection)) {
|
|
129
|
+
this.socketMap.remove(connection);
|
|
130
|
+
console.log(`Removed connection. ${this.socketMap.getArray().length} sockets remaining.`);
|
|
131
|
+
connection.destroy();
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
connection.on('close', cleanupConnection);
|
|
135
|
+
connection.on('error', cleanupConnection);
|
|
136
|
+
connection.on('end', cleanupConnection);
|
|
137
|
+
connection.on('timeout', cleanupConnection);
|
|
138
|
+
});
|
|
139
|
+
this.httpsServer.listen(this.options.port);
|
|
140
|
+
console.log(`NetworkProxy -> OK: now listening for new connections on port ${this.options.port}`);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Internal async handler for processing HTTP/HTTPS requests.
|
|
144
|
+
*/
|
|
145
|
+
async handleRequest(originRequest, originResponse) {
|
|
146
|
+
const endOriginReqRes = (statusArg = 404, messageArg = 'This route is not available on this server.', headers = {}) => {
|
|
147
|
+
originResponse.writeHead(statusArg, messageArg);
|
|
148
|
+
originResponse.end(messageArg);
|
|
149
|
+
if (originRequest.socket !== originResponse.socket) {
|
|
150
|
+
console.log('hey, something is strange.');
|
|
151
|
+
}
|
|
152
|
+
originResponse.destroy();
|
|
153
|
+
};
|
|
154
|
+
console.log(`got request: ${originRequest.headers.host}${plugins.url.parse(originRequest.url).path}`);
|
|
155
|
+
const destinationConfig = this.router.routeReq(originRequest);
|
|
156
|
+
if (!destinationConfig) {
|
|
157
|
+
console.log(`${originRequest.headers.host} can't be routed properly. Terminating request.`);
|
|
158
|
+
endOriginReqRes();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// authentication
|
|
162
|
+
if (destinationConfig.authentication) {
|
|
163
|
+
const authInfo = destinationConfig.authentication;
|
|
164
|
+
switch (authInfo.type) {
|
|
165
|
+
case 'Basic': {
|
|
166
|
+
const authHeader = originRequest.headers.authorization;
|
|
167
|
+
if (!authHeader) {
|
|
168
|
+
return endOriginReqRes(401, 'Authentication required', {
|
|
169
|
+
'WWW-Authenticate': 'Basic realm="Access to the staging site", charset="UTF-8"',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
if (!authHeader.includes('Basic ')) {
|
|
173
|
+
return endOriginReqRes(401, 'Authentication required', {
|
|
174
|
+
'WWW-Authenticate': 'Basic realm="Access to the staging site", charset="UTF-8"',
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const authStringBase64 = authHeader.replace('Basic ', '');
|
|
178
|
+
const authString = plugins.smartstring.base64.decode(authStringBase64);
|
|
179
|
+
const userPassArray = authString.split(':');
|
|
180
|
+
const user = userPassArray[0];
|
|
181
|
+
const pass = userPassArray[1];
|
|
182
|
+
if (user === authInfo.user && pass === authInfo.pass) {
|
|
183
|
+
console.log('Request successfully authenticated');
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
return endOriginReqRes(403, 'Forbidden: Wrong credentials');
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
default:
|
|
191
|
+
return endOriginReqRes(403, 'Forbidden: unsupported authentication method configured. Please report to the admin.');
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
let destinationUrl;
|
|
195
|
+
if (destinationConfig) {
|
|
196
|
+
destinationUrl = `http://${destinationConfig.destinationIp}:${destinationConfig.destinationPort}${originRequest.url}`;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
return endOriginReqRes();
|
|
200
|
+
}
|
|
201
|
+
console.log(destinationUrl);
|
|
202
|
+
try {
|
|
203
|
+
const proxyResponse = await plugins.smartrequest.request(destinationUrl, {
|
|
204
|
+
method: originRequest.method,
|
|
205
|
+
headers: {
|
|
206
|
+
...originRequest.headers,
|
|
207
|
+
'X-Forwarded-Host': originRequest.headers.host,
|
|
208
|
+
'X-Forwarded-Proto': 'https',
|
|
209
|
+
},
|
|
210
|
+
keepAlive: true,
|
|
211
|
+
}, true, // streaming (keepAlive)
|
|
212
|
+
(proxyRequest) => {
|
|
213
|
+
originRequest.on('data', (data) => {
|
|
214
|
+
proxyRequest.write(data);
|
|
215
|
+
});
|
|
216
|
+
originRequest.on('end', () => {
|
|
217
|
+
proxyRequest.end();
|
|
218
|
+
});
|
|
219
|
+
originRequest.on('error', () => {
|
|
220
|
+
proxyRequest.end();
|
|
221
|
+
});
|
|
222
|
+
originRequest.on('close', () => {
|
|
223
|
+
proxyRequest.end();
|
|
224
|
+
});
|
|
225
|
+
originRequest.on('timeout', () => {
|
|
226
|
+
proxyRequest.end();
|
|
227
|
+
originRequest.destroy();
|
|
228
|
+
});
|
|
229
|
+
proxyRequest.on('error', () => {
|
|
230
|
+
endOriginReqRes();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
originResponse.statusCode = proxyResponse.statusCode;
|
|
234
|
+
console.log(proxyResponse.statusCode);
|
|
235
|
+
for (const defaultHeader of Object.keys(this.defaultHeaders)) {
|
|
236
|
+
originResponse.setHeader(defaultHeader, this.defaultHeaders[defaultHeader]);
|
|
237
|
+
}
|
|
238
|
+
for (const header of Object.keys(proxyResponse.headers)) {
|
|
239
|
+
originResponse.setHeader(header, proxyResponse.headers[header]);
|
|
240
|
+
}
|
|
241
|
+
proxyResponse.on('data', (data) => {
|
|
242
|
+
originResponse.write(data);
|
|
243
|
+
});
|
|
244
|
+
proxyResponse.on('end', () => {
|
|
245
|
+
originResponse.end();
|
|
246
|
+
});
|
|
247
|
+
proxyResponse.on('error', () => {
|
|
248
|
+
originResponse.destroy();
|
|
249
|
+
});
|
|
250
|
+
proxyResponse.on('close', () => {
|
|
251
|
+
originResponse.end();
|
|
252
|
+
});
|
|
253
|
+
proxyResponse.on('timeout', () => {
|
|
254
|
+
originResponse.end();
|
|
255
|
+
originResponse.destroy();
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
console.error('Error while processing request:', error);
|
|
260
|
+
endOriginReqRes(502, 'Bad Gateway: Error processing the request');
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async updateProxyConfigs(proxyConfigsArg) {
|
|
264
|
+
console.log(`got new proxy configs`);
|
|
265
|
+
this.proxyConfigs = proxyConfigsArg;
|
|
266
|
+
this.router.setNewProxyConfigs(proxyConfigsArg);
|
|
267
|
+
for (const hostCandidate of this.proxyConfigs) {
|
|
268
|
+
const existingHostNameConfig = this.alreadyAddedReverseConfigs[hostCandidate.hostName];
|
|
269
|
+
if (!existingHostNameConfig) {
|
|
270
|
+
this.alreadyAddedReverseConfigs[hostCandidate.hostName] = hostCandidate;
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
if (existingHostNameConfig.publicKey === hostCandidate.publicKey &&
|
|
274
|
+
existingHostNameConfig.privateKey === hostCandidate.privateKey) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
this.alreadyAddedReverseConfigs[hostCandidate.hostName] = hostCandidate;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
this.httpsServer.addContext(hostCandidate.hostName, {
|
|
282
|
+
cert: hostCandidate.publicKey,
|
|
283
|
+
key: hostCandidate.privateKey,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
async addDefaultHeaders(headersArg) {
|
|
288
|
+
for (const headerKey of Object.keys(headersArg)) {
|
|
289
|
+
this.defaultHeaders[headerKey] = headersArg[headerKey];
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
async stop() {
|
|
293
|
+
const done = plugins.smartpromise.defer();
|
|
294
|
+
this.httpsServer.close(() => {
|
|
295
|
+
done.resolve();
|
|
296
|
+
});
|
|
297
|
+
for (const socket of this.socketMap.getArray()) {
|
|
298
|
+
socket.destroy();
|
|
299
|
+
}
|
|
300
|
+
await done.promise;
|
|
301
|
+
clearInterval(this.heartbeatInterval);
|
|
302
|
+
console.log('NetworkProxy -> OK: Server has been stopped and all connections closed.');
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5uZXR3b3JrcHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm5ldHdvcmtwcm94eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbEQsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFDN0IsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQVVwQyxNQUFNLE9BQU8sWUFBWTtJQWN2QixZQUFZLFVBQWdDO1FBWnJDLGlCQUFZLEdBQWtELEVBQUUsQ0FBQztRQUVqRSxXQUFNLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUMzQixjQUFTLEdBQUcsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBc0IsQ0FBQztRQUM1RCxtQkFBYyxHQUE4QixFQUFFLENBQUM7UUFJL0MsK0JBQTBCLEdBRTdCLEVBQUUsQ0FBQztRQUdMLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDO1FBQzFCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUMvRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBRS9ELElBQUksQ0FBQztZQUNILElBQUksQ0FBQyxtQkFBbUIsR0FBRztnQkFDekIsR0FBRyxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLEVBQUUsTUFBTSxDQUFDO2dCQUM1RCxJQUFJLEVBQUUs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
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export declare class Port80Handler {
|
|
2
|
+
private domainCertificates;
|
|
3
|
+
private server;
|
|
4
|
+
private acmeClient;
|
|
5
|
+
private accountKey;
|
|
6
|
+
constructor();
|
|
7
|
+
/**
|
|
8
|
+
* Adds a domain to be managed.
|
|
9
|
+
* @param domain The domain to add.
|
|
10
|
+
*/
|
|
11
|
+
addDomain(domain: string): void;
|
|
12
|
+
/**
|
|
13
|
+
* Removes a domain from management.
|
|
14
|
+
* @param domain The domain to remove.
|
|
15
|
+
*/
|
|
16
|
+
removeDomain(domain: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Lazy initialization of the ACME client.
|
|
19
|
+
* Uses Let’s Encrypt’s production directory (for testing you might switch to staging).
|
|
20
|
+
*/
|
|
21
|
+
private getAcmeClient;
|
|
22
|
+
/**
|
|
23
|
+
* Handles incoming HTTP requests on port 80.
|
|
24
|
+
* If the request is for an ACME challenge, it responds with the key authorization.
|
|
25
|
+
* If the domain has a certificate, it redirects to HTTPS; otherwise, it initiates certificate issuance.
|
|
26
|
+
*/
|
|
27
|
+
private handleRequest;
|
|
28
|
+
/**
|
|
29
|
+
* Serves the ACME HTTP-01 challenge response.
|
|
30
|
+
*/
|
|
31
|
+
private handleAcmeChallenge;
|
|
32
|
+
/**
|
|
33
|
+
* Uses acme-client to perform a full ACME HTTP-01 challenge to obtain a certificate.
|
|
34
|
+
* On success, it stores the certificate and key in memory and clears challenge data.
|
|
35
|
+
*/
|
|
36
|
+
private obtainCertificate;
|
|
37
|
+
}
|