-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcrashhandler.js
More file actions
155 lines (137 loc) · 4.8 KB
/
crashhandler.js
File metadata and controls
155 lines (137 loc) · 4.8 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
import tls from 'tls';
import http, { IncomingMessage, ServerResponse } from 'http';
import https from 'https';
import config from './config.json' with { type: 'json' };
import { getCertificate } from './CertManager.js';
import { reloadProxy, reloadWebServer } from './index.js';
/**
* Performs basic authentication
* @param {IncomingMessage} req
* @param {ServerResponse} res
* @param {string} user
* @param {string} pass
* @returns {boolean} successful authentication
*/
function basicAuth(req, res, user, pass, realm="Debug Access") {
// Check for basic auth header
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Basic ')) {
res.writeHead(401, {
'Content-Type': 'text/plain',
'WWW-Authenticate': `Basic realm="${realm}"`
});
res.end("Unauthorized");
return false;
}
// Verify credentials
const base64Credentials = authHeader.split(' ')[1];
const credentials = Buffer.from(base64Credentials, 'base64').toString('ascii');
const [username, password] = credentials.split(':');
if (username !== user || password !== pass) {
res.writeHead(403, { 'Content-Type': 'text/plain' });
res.end("Forbidden");
return false;
}
return true;
}
// Fallback server logic
const serverLogic = (req, res) => {
const authorized = basicAuth(req, res, config.fallback.auth.username, config.fallback.auth.password);
if (!authorized) {
return;
}
if (req.url.includes('/.well-known/status')) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end(JSON.stringify({
ok: false,
status: "down",
reason: "error",
revisionId: "unknown",
}));
} else if (req.url.includes("/.debug/reset")) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Resetting...');
process.exit(0);
} else if (req.url.includes("/.debug/reboot")) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Rebooting...');
// Get all active connections and destroy them
const server = req.socket.server;
server._connections = 0;
server._handle.close();
server.emit('close');
// Force destroy any remaining sockets
server.getConnections((err, count) => {
if (err) console.error('Error getting connections:', err);
if (count > 0) {
server.connections.forEach(socket => socket.destroy());
}
});
// Close the server
server.close();
// Restart the server
setTimeout(() => {
reloadProxy();
reloadWebServer();
}, 5000);
} else {
res.writeHead(503, { 'Content-Type': 'text/plain' });
res.end('Service Unavailable');
}
};
function startServer(httpPort, httpsPort) {
let httpServer, httpsServer;
if (httpPort) {
httpServer = http.createServer(serverLogic);
httpServer.listen(httpPort, () => {
console.log(`HTTP fallback server listening on port ${httpPort}`);
});
}
if (httpsPort) {
httpsServer = https.createServer({
SNICallback: (hostname, cb) => {
const cert = getCertificate(hostname);
cb(null, tls.createSecureContext(cert));
},
}, serverLogic);
httpsServer.listen(httpsPort, () => {
console.log(`HTTPS fallback server listening on port ${httpsPort}`);
});
}
return { httpServer, httpsServer };
}
export default function handleCrash(application, code) {
if (config.fallback.disable) {
console.info(`${application} exited with code ${code}. Stopping main process.`);
process.exit(code);
}
switch (application) {
case "proxy": {
console.log(`Proxy server crashed with code ${code}. Starting fallback...`);
try {
startServer(config.ports[0], config.ports[1]);
} catch (error) {
console.error("Error starting proxy fallback server:", error);
process.exit(code);
}
break;
}
case "management": {
console.log(`Management server crashed with code ${code}. Starting fallback...`);
try {
startServer(config.management.port, null);
} catch (error) {
console.error("Error starting management fallback server:", error);
process.exit(code);
}
break;
}
default: {
console.log(`Unknown application "${application}" crashed with code ${code}.`);
setTimeout(() => {
process.exit(code);
}, 5000);
break;
}
}
}