-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.js
More file actions
193 lines (160 loc) · 6.18 KB
/
index.js
File metadata and controls
193 lines (160 loc) · 6.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import { readdirSync, readFileSync, existsSync } from 'fs';
import { readdir, readFile, unlink } from 'fs/promises';
import { join } from 'path';
import pkg from 'http-proxy';
const { createProxyServer } = pkg;
import { createServer as createServerHttp, IncomingMessage, ServerResponse } from 'http';
import { createServer as createServerHttps } from 'https';
import tls from 'tls';
import WebSocket, { WebSocketServer } from 'ws';
import { pathToFileURL } from 'url';
import Greenlock from "greenlock";
import http01Lib from "acme-http-01-standalone";
const http01 = http01Lib.create({});
// import config from './config.json' with {
// type: "json"
// };
// run "npm run migrate" to update config.json references instead
// import updateConfigRefs from './migration.js';
// await updateConfigRefs(join(process.cwd(), 'config.json'));
const config = (await import('./config.json', {
with: { type: "json" }
})).default;
import { fork } from 'child_process';
import handleCrash from './crashhandler.js';
import { getCertificate } from './CertManager.js';
if (existsSync(join(process.cwd(), 'auth.json')) && config.cleanAuthFile) {
unlink(join(process.cwd(), 'auth.json')); // Remove old auth file
}
if (config.acme.enabled) {
let acmeFork = fork('./acme.js');
const reloadAcme = () => {
acmeFork.kill();
acmeFork = fork('./acme.js');
};
let lastAcmeReload = Date.now();
setInterval(() => {
const now = Date.now();
const daysSinceLastReload = (now - lastAcmeReload) / (24 * 60 * 60 * 1000);
if (daysSinceLastReload >= config.acme.checkInterval) {
reloadAcme();
lastAcmeReload = now;
}
}, 60 * 60 * 1000); // Check every hour
acmeFork.on("exit", (code) => {
console.log(`ACME server exited with code ${code}`);
});
acmeFork.on("error", (err) => {
console.error("ACME server error:", err);
});
}
// Init proxy as clusters https://nodejs.org/api/cluster.html
let proxyFork = fork('./proxy.js');
proxyFork.on("exit", (code) => {
console.log(`Proxy server exited with code ${code}`);
handleCrash("proxy", code);
});
proxyFork.on("error", (err) => {
console.error("Proxy server error:", err);
});
proxyFork.on("message", (message) => {
if (message === 'reload') {
reloadProxy();
} else {
console.log("Unknown message from proxy server:", message);
}
});
export const reloadProxy = () => {
proxyFork.kill();
proxyFork = fork('./proxy.js');
};
// experimental, use with caution
export let reloadWebServer = () => {
throw new Error("Web server not initialized");
}
if (config.management.enabled) {
let webServerFork = fork("./web/server.js");
webServerFork.on("exit", (code) => {
console.log(`Web server exited with code ${code}`);
handleCrash("management", code);
});
webServerFork.on("message", (message) => {
if (message === 'reload') {
reloadProxy();
} else {
console.log("Unknown message from web server:", message);
}
});
reloadWebServer = () => {
webServerFork.kill();
webServerFork = fork("./web/server.js");
}
}
// Test server
if (config.testserver.enabled) {
const testServer = createServerHttp((req, res) => {
console.debug('Test server request', req.url);
console.debug(req.headers);
if (!config.testserver.fail) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end("OK");
} else {
// do nothing, cause a timeout
}
});
testServer.listen(config.testserver.port, () => {
console.log(`Test server listening on port ${config.testserver.port}`);
});
if (config.testserver.websocket) {
const wss = new WebSocketServer({
server: testServer
});
wss.on("headers", (headers, req) => {
console.log('Test server WebSocket headers:', headers, req.url);
});
wss.on('connection', (ws, req) => {
console.log('Test server WebSocket connection');
// console.debug('Test server WebSocket headers:', ws.protocol, ws._socket.server._connectionKey);
ws.on('message', (message) => {
console.log('Test server WebSocket message:', message.toString());
ws.send(message.toString());
});
ws.send('Hello from the test server!');
setTimeout(() => {
ws.close(1000, 'Goodbye: timeout');
}, 10000);
});
// Secure WebSocket test server
if (false) {
// try to replicate this error
// Error during request to /agent.ashx: write EPROTO 80486B1C5E700000:error:0A00010B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:354:
// secure server
const httpsserver = createServerHttps(getCertificate("localhost"), (req, res) => { });
// Create secure WebSocket server
const wsss = new WebSocketServer({
server: httpsserver
});
wsss.on("headers", (headers, req) => {
console.log('Test server secure WebSocket headers:', headers, req.url);
});
wsss.on('connection', (ws, req) => {
console.log('Test server secure WebSocket connection');
// console.debug('Test server WebSocket headers:', ws.protocol, ws._socket.server._connectionKey);
ws.on('message', (message) => {
console.log('Test server secure WebSocket message:', message.toString());
ws.send(message.toString());
});
ws.send('Hello from the secure test server!');
setTimeout(() => {
ws.close(1000, 'Goodbye: timeout');
}, 10000);
});
wsss.on('error', (error) => {
console.error('Secure WebSocket server error:', error);
});
httpsserver.listen(config.testserver.port + 1, () => {
console.log(`Secure test server listening on port ${config.testserver.port + 1}`);
});
}
}
}