mwc-proxy 0.0.1

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/api.js ADDED
@@ -0,0 +1,526 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.parseSocksProxy = exports.currentState = void 0;
40
+ exports.createProxyMiddleware = createProxyMiddleware;
41
+ const net_1 = __importStar(require("net"));
42
+ const http_1 = __importDefault(require("http"));
43
+ const https_1 = __importDefault(require("https"));
44
+ const crypto_1 = __importDefault(require("crypto"));
45
+ const fs_1 = __importDefault(require("fs"));
46
+ const path_1 = __importDefault(require("path"));
47
+ const express_1 = __importDefault(require("express"));
48
+ const express_ws_1 = __importDefault(require("express-ws"));
49
+ const socks_1 = require("socks");
50
+ const authEndpoint_1 = __importDefault(require("./authEndpoint"));
51
+ const metrics_1 = require("./metrics");
52
+ const signal_client_1 = require("./signal-client");
53
+ // Import version from package.json
54
+ const packageJson = require('../package.json');
55
+ const VERSION = packageJson.version;
56
+ function generateToken() {
57
+ return crypto_1.default.randomBytes(32).toString('hex');
58
+ }
59
+ function checkTo(allowed, requested) {
60
+ if (!Array.isArray(allowed)) {
61
+ allowed = [allowed];
62
+ }
63
+ // For each rule
64
+ for (const to of allowed) {
65
+ if ((to.host === requested.host || !to.host) && (to.port === requested.port || !to.port)) {
66
+ return !to.blacklist;
67
+ }
68
+ }
69
+ // No rule found, access denied
70
+ return false;
71
+ }
72
+ exports.currentState = {
73
+ activeConnections: {},
74
+ pendingConnections: {},
75
+ everConnected: 0,
76
+ };
77
+ function ipToNumber(ip) {
78
+ if ((0, net_1.isIPv4)(ip)) {
79
+ const parts = ip.split('.');
80
+ let result = 0;
81
+ for (const part of parts) {
82
+ result = result * 256 + Number.parseInt(part, 10);
83
+ }
84
+ return BigInt(result);
85
+ }
86
+ // IPv6
87
+ const parts = ip.split(':').filter(part => part !== '');
88
+ let result = BigInt(0);
89
+ for (const part of parts) {
90
+ // eslint-disable-next-line no-bitwise
91
+ result = (result << BigInt(16)) + BigInt(`0x${part}`);
92
+ }
93
+ return result;
94
+ }
95
+ const getProxy = (proxies, requestIp) => {
96
+ const index = Number(ipToNumber(requestIp) % BigInt(proxies.length));
97
+ return proxies[index];
98
+ };
99
+ function createProxyMiddleware(options = {}, connectionListener = ws => { }) {
100
+ const startTimeFormmated = new Intl.DateTimeFormat('en', {
101
+ year: 'numeric',
102
+ month: '2-digit',
103
+ day: '2-digit',
104
+ hour: 'numeric',
105
+ }).format(new Date());
106
+ let myLog = typeof options.log === 'function' ? options.log : () => { };
107
+ if (options.log === true)
108
+ myLog = console.log;
109
+ const app = (0, express_1.default)();
110
+ app.use(express_1.default.urlencoded({ extended: true }));
111
+ app.use(express_1.default.json());
112
+ if (options.metricsEndpoint !== false) {
113
+ app.use(metrics_1.metricsMiddleware);
114
+ }
115
+ const urlRoot = options.urlRoot ?? '/api/vm/net';
116
+ let server = options.server;
117
+ if (!server) {
118
+ if (options.https) {
119
+ const key = fs_1.default.readFileSync(path_1.default.join(__dirname, './key.pem'));
120
+ const cert = fs_1.default.readFileSync(path_1.default.join(__dirname, './cert.pem'));
121
+ server = https_1.default.createServer({
122
+ key,
123
+ cert,
124
+ });
125
+ }
126
+ else {
127
+ server = http_1.default.createServer();
128
+ }
129
+ }
130
+ const sockets = {};
131
+ if (options.allowOrigin) {
132
+ let { allowOrigin } = options;
133
+ if (typeof options.allowOrigin !== 'string') {
134
+ allowOrigin = options.allowOrigin ? '*' : '';
135
+ }
136
+ if (allowOrigin) {
137
+ // Set Access-Control headers (CORS)
138
+ app.use((req, res, next) => {
139
+ if (!req.path.startsWith(urlRoot) && !options.allowOriginApp) {
140
+ next();
141
+ return;
142
+ }
143
+ res.header('Access-Control-Allow-Origin', allowOrigin);
144
+ if (req.method.toUpperCase() === 'OPTIONS') {
145
+ // Preflighted requests
146
+ res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
147
+ res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
148
+ res.header('Access-Control-Max-Age', '1_728_000'); // Access-Control headers cached for 20 days
149
+ }
150
+ next();
151
+ });
152
+ }
153
+ }
154
+ const processConnectionRequest = async (req, res, proxies, connectionTimeLimit) => {
155
+ // Generate unique request ID for tracking pending connections
156
+ const requestId = `${Date.now()}-${Math.random().toString(36).slice(7)}`;
157
+ const cleanupPendingConnection = () => {
158
+ delete exports.currentState.pendingConnections[requestId];
159
+ };
160
+ try {
161
+ const { host, port } = req.body;
162
+ if (!host || !port) {
163
+ res.status(400).send({
164
+ code: 400,
165
+ error: 'No host and port specified',
166
+ });
167
+ return;
168
+ }
169
+ if (options.to && !checkTo(options.to, { host, port })) {
170
+ res.status(403).send({
171
+ code: 403,
172
+ error: 'Destination not allowed',
173
+ });
174
+ return;
175
+ }
176
+ const { activeConnections, pendingConnections } = exports.currentState;
177
+ const ip =
178
+ // (req.headers['cf-connecting-ip'] as string | undefined) ||
179
+ req.headers['x-forwarded-for']?.split?.(',')?.[0] || req.connection?.remoteAddress || req.socket.remoteAddress || req.ip;
180
+ const isIpv6 = ip.includes(':');
181
+ // Count both active and pending connections to prevent race condition exploitation
182
+ const activeCount = Object.values(activeConnections).filter(c => c.ip === ip).length;
183
+ const pendingCount = Object.values(pendingConnections).filter(c => c.ip === ip).length;
184
+ const totalCount = activeCount + pendingCount;
185
+ const maxConnections = options.maxConnectionsPerIp ?? 5;
186
+ if (totalCount >= maxConnections) {
187
+ const errorMessage = options.mwcCallbacks?.getTooManyConnectionsMessage
188
+ ? options.mwcCallbacks.getTooManyConnectionsMessage(totalCount, maxConnections)
189
+ : `Too many connections from the same IP (${totalCount}/${maxConnections}). Please wait for existing connections to close.`;
190
+ res.status(429).send({
191
+ code: 429,
192
+ error: errorMessage,
193
+ });
194
+ return;
195
+ }
196
+ // Register this as a pending connection
197
+ exports.currentState.pendingConnections[requestId] = {
198
+ ip,
199
+ startTime: Date.now(),
200
+ };
201
+ // Clean up pending connection on response close/error
202
+ res.on('close', cleanupPendingConnection);
203
+ res.on('finish', cleanupPendingConnection);
204
+ // Safety timeout: clean up pending connection after 30 seconds if still pending
205
+ const pendingTimeout = setTimeout(() => {
206
+ cleanupPendingConnection();
207
+ }, 30_000);
208
+ res.on('close', () => clearTimeout(pendingTimeout));
209
+ res.on('finish', () => clearTimeout(pendingTimeout));
210
+ if (isIpv6 && options.allowIPv6 === false) {
211
+ res.status(403).send({
212
+ code: 403,
213
+ error: 'IPv6 not allowed',
214
+ });
215
+ return;
216
+ }
217
+ const lang = req.headers['accept-language']?.split(',')[0];
218
+ const logC = (addStr = '') => {
219
+ myLog(`[C]${addStr} ${host}:${port} from ${ip} (${lang})`);
220
+ };
221
+ let socket;
222
+ const connectTimeout = 1000 * 8;
223
+ if (proxies) {
224
+ const proxy = getProxy(proxies, ip);
225
+ logC(` ${proxies.indexOf(proxy)}`);
226
+ ({ socket } = await socks_1.SocksClient.createConnection({
227
+ proxy: (0, exports.parseSocksProxy)(proxy),
228
+ command: 'connect',
229
+ destination: {
230
+ host,
231
+ port: Number(port),
232
+ },
233
+ timeout: connectTimeout,
234
+ }));
235
+ }
236
+ else {
237
+ logC();
238
+ socket = net_1.default.connect({
239
+ host,
240
+ port: Number(port),
241
+ timeout: connectTimeout,
242
+ });
243
+ }
244
+ socket.setTimeout(1000 * 6);
245
+ socket.on('timeout', () => {
246
+ cleanupPendingConnection();
247
+ if (!res.finished) {
248
+ res.status(504).send({
249
+ code: 504,
250
+ error: `Connection timed out. Ensure the server ${host} is reachable and the port ${port} is open.`
251
+ });
252
+ }
253
+ socket.end();
254
+ });
255
+ socket.on('error', err => {
256
+ cleanupPendingConnection();
257
+ if (res.headersSent)
258
+ return;
259
+ res.status(500).send({
260
+ code: 500,
261
+ error: err,
262
+ });
263
+ });
264
+ socket.on('connect', () => {
265
+ cleanupPendingConnection();
266
+ if (res.headersSent) {
267
+ socket.end();
268
+ return;
269
+ }
270
+ // Generate a token for this connection
271
+ const token = generateToken();
272
+ sockets[token] = socket;
273
+ exports.currentState.everConnected++;
274
+ activeConnections[token] = {
275
+ startTime: Date.now(),
276
+ ip,
277
+ host,
278
+ };
279
+ metrics_1.updateMetrics.addConnection();
280
+ // Notify MWC of connection change if available
281
+ if (options.mwcCallbacks?.onConnectionChange) {
282
+ options.mwcCallbacks.onConnectionChange(Object.keys(activeConnections).length);
283
+ }
284
+ // Remove the socket from the list when closed
285
+ socket.on('close', hadError => {
286
+ myLog(`[D${hadError ? '-E' : ''}] ${host}:${port} (${activeConnections[token] && (Date.now() - activeConnections[token].startTime) / 1000}, ${token})`);
287
+ if (sockets[token]) {
288
+ const duration = (Date.now() - activeConnections[token].startTime) / 1000;
289
+ const connectionInfo = activeConnections[token];
290
+ metrics_1.updateMetrics.updateConnectionDuration(token, duration, host, connectionInfo.ip);
291
+ metrics_1.updateMetrics.removeConnection();
292
+ delete sockets[token];
293
+ delete activeConnections[token];
294
+ // Notify MWC of connection change if available
295
+ if (options.mwcCallbacks?.onConnectionChange) {
296
+ options.mwcCallbacks.onConnectionChange(Object.keys(activeConnections).length);
297
+ }
298
+ }
299
+ });
300
+ const { origin } = req.headers;
301
+ // todo also print username
302
+ myLog(`[U] ${req.body.host}:${req.body.port} ${origin} (${token})`);
303
+ const remote = socket.address();
304
+ res.send({
305
+ token,
306
+ remote,
307
+ });
308
+ });
309
+ const timeout = connectionTimeLimit
310
+ ? setTimeout(() => {
311
+ // todo warn first!
312
+ setTimeout(() => {
313
+ socket.end();
314
+ }, 1000 * 200);
315
+ }, connectionTimeLimit)
316
+ : undefined;
317
+ socket.on('close', () => {
318
+ if (timeout)
319
+ clearTimeout(timeout);
320
+ });
321
+ if (proxies) {
322
+ // socksclient already gives us a connected socket
323
+ socket.emit('connect');
324
+ }
325
+ socket.on('error', (err) => {
326
+ cleanupPendingConnection();
327
+ if (res.writableEnded) {
328
+ myLog(`Socket error after response closed: ${err}`);
329
+ return;
330
+ }
331
+ res.status(502).send({
332
+ code: 502,
333
+ error: `Socket error: ${err.code}`,
334
+ details: err,
335
+ });
336
+ });
337
+ if (connectionListener) {
338
+ connectionListener(socket);
339
+ }
340
+ }
341
+ catch (err) {
342
+ // mainly for socks awaiting
343
+ cleanupPendingConnection();
344
+ try {
345
+ res.status(500).send({
346
+ code: 500,
347
+ error: err.message,
348
+ });
349
+ }
350
+ catch { }
351
+ }
352
+ };
353
+ app.post(`${urlRoot}/connect`, async (req, res) => {
354
+ // Allow MWC to handle request with custom routing logic
355
+ if (options.mwcCallbacks?.handleConnectionRequest) {
356
+ const handled = await options.mwcCallbacks.handleConnectionRequest(req, res, async (proxies, timeLimit) => {
357
+ await processConnectionRequest(req, res, proxies, timeLimit);
358
+ });
359
+ if (handled)
360
+ return;
361
+ }
362
+ // Default: normal connection with no proxies
363
+ const timeLimit = 1000 * 60 * 60 * 12; // 12 hours
364
+ await processConnectionRequest(req, res, undefined, timeLimit);
365
+ });
366
+ if (options.debugUrlEndpoint !== false) {
367
+ app.get(`${urlRoot}/debug`, (req, res) => {
368
+ const headers = Object.entries(req.headers);
369
+ // print full request url including host + query params
370
+ res.send(`<pre>${req.protocol}://${req.get('host')}${req.originalUrl}\n\n${headers.map(([key, value]) => `${key}: ${value}`).join('\n')}</pre>`);
371
+ });
372
+ }
373
+ const authEndpoint = `${urlRoot}/auth`;
374
+ const sessionEndpoint = `${urlRoot}/session`;
375
+ app.get(`${urlRoot}/connect`, (req, res) => {
376
+ const json = {
377
+ version: VERSION,
378
+ capabilities: {
379
+ authEndpoint,
380
+ sessionEndpoint,
381
+ // ping: true
382
+ },
383
+ };
384
+ // Add custom data from MWC callbacks if available
385
+ if (options.mwcCallbacks?.getConnectData) {
386
+ const customData = options.mwcCallbacks.getConnectData();
387
+ Object.assign(json, customData);
388
+ }
389
+ res.send(json);
390
+ });
391
+ app.get(`${urlRoot}/connections`, (req, res) => {
392
+ const accessCodeQs = req.query.code;
393
+ const basicInfo = [
394
+ `Ever connected since ${startTimeFormmated}: ${exports.currentState.everConnected}`,
395
+ `Live: ${Object.keys(exports.currentState.activeConnections).length}`,
396
+ ];
397
+ if (!process.env.ACCESS_CODE || accessCodeQs !== process.env.ACCESS_CODE) {
398
+ try {
399
+ res.status(403).send({
400
+ code: 403,
401
+ error: 'Access code required',
402
+ basicInfo,
403
+ });
404
+ }
405
+ catch { }
406
+ return;
407
+ }
408
+ const stateFormatted = [
409
+ ...Object.entries(exports.currentState.activeConnections).map(([token, { startTime, ip, host }], i) => `${i + 1}. (${(Date.now() - startTime) / 1000}s): ${ip} -> ${host}`),
410
+ ...basicInfo,
411
+ ].join('\n');
412
+ res.send(stateFormatted);
413
+ });
414
+ (0, authEndpoint_1.default)(app, authEndpoint, sessionEndpoint, str => myLog(str), urlRoot, options);
415
+ const wss = (0, express_ws_1.default)(app, server);
416
+ const appUntyhped = app;
417
+ appUntyhped.ws(`${urlRoot}/ping`, (ws, req) => {
418
+ try {
419
+ if (options.onPing) {
420
+ options.onPing(req);
421
+ }
422
+ ws.on('message', (data) => {
423
+ if (typeof data === 'string' && data.startsWith('ping:')) {
424
+ const startTime = process.hrtime();
425
+ const pingId = data.slice('ping:'.length);
426
+ ws.send(`pong:${pingId}:${process.hrtime(startTime)[1] / 1_000_000}`, () => { });
427
+ }
428
+ });
429
+ }
430
+ catch {
431
+ // console.error('Error handling ping WebSocket connection:', err)
432
+ }
433
+ });
434
+ appUntyhped.ws(`${urlRoot}/socket`, (ws, req) => {
435
+ const { token } = req.query;
436
+ if (!sockets[token]) {
437
+ console.warn(`WARN: Unknown TCP connection with token "${token}"`);
438
+ ws.close();
439
+ return;
440
+ }
441
+ const socket = sockets[token];
442
+ //delete sockets[token];
443
+ // myLog(`Forwarding socket with token ${token}`)
444
+ ws.on('message', data => {
445
+ if (typeof data === 'string' && data.startsWith('ping:')) {
446
+ ws.send(`pong:${data.slice('ping:'.length)}`);
447
+ return;
448
+ }
449
+ socket.write(data, 'binary', () => {
450
+ //myLog('Sent: ', data.toString());
451
+ });
452
+ });
453
+ socket.on('data', chunk => {
454
+ //myLog('Received: ', chunk.toString());
455
+ // Providing a callback is important, otherwise errors can be thrown
456
+ ws.send(chunk, { binary: true }, err => { });
457
+ });
458
+ socket.on('end', () => {
459
+ // myLog(`TCP connection closed by remote (${token})`)
460
+ ws.close();
461
+ });
462
+ socket.on('error', err => {
463
+ const message = err.code === 'EADDRNOTAVAIL' ? 'Minecraft server is not reachable anymore.' : `Issue with the connection to the Minecraft server: ${err.message}`;
464
+ ws.send(`proxy-shutdown:${message}`, () => { });
465
+ });
466
+ ws.on('close', () => {
467
+ socket.end();
468
+ // myLog(`Websocket connection closed (${token})`)
469
+ });
470
+ });
471
+ app.on('mount', parentApp => {
472
+ // @see https://github.com/strongloop/express/blob/master/lib/application.js#L615
473
+ parentApp.listen = function () {
474
+ server.addListener('request', this);
475
+ // eslint-disable-next-line prefer-spread, prefer-rest-params
476
+ return server.listen.apply(server, arguments);
477
+ };
478
+ });
479
+ if (options.signal) {
480
+ const signalOpts = options.signal;
481
+ const signalClient = new signal_client_1.SignalClient({
482
+ signalServerUrl: signalOpts.serverUrl,
483
+ description: signalOpts.description,
484
+ domain: signalOpts.domain,
485
+ listenPort: signalOpts.listenPort,
486
+ urlRoot: options.urlRoot ?? '/api/vm/net',
487
+ getSystemInfo: () => ({
488
+ connectedPlayers: Object.keys(exports.currentState.activeConnections).length,
489
+ ...signalOpts.getExtraSystemInfo?.(),
490
+ }),
491
+ });
492
+ const stopSignal = () => signalClient.stop();
493
+ process.once('SIGTERM', stopSignal);
494
+ process.once('SIGINT', stopSignal);
495
+ }
496
+ return app;
497
+ }
498
+ exports.default = createProxyMiddleware;
499
+ const parseSocksProxy = (proxy) => {
500
+ const proxyParts = proxy.split('@');
501
+ if (proxyParts.length === 1) {
502
+ const portStr = proxyParts[0].split(':')[1];
503
+ if (!portStr)
504
+ throw new Error('Missing port in socks5 proxy');
505
+ return {
506
+ ipaddress: proxyParts[0],
507
+ port: Number.parseInt(portStr, 10),
508
+ type: 5,
509
+ };
510
+ }
511
+ if (proxyParts.length === 2) {
512
+ const [ipaddress, portStr] = proxyParts[1].split(':');
513
+ const [userId, password] = proxyParts[0].split(':');
514
+ if (!portStr)
515
+ throw new Error('Missing port in socks5 proxy');
516
+ return {
517
+ ipaddress,
518
+ port: Number.parseInt(portStr, 10),
519
+ userId: userId,
520
+ password: password || undefined,
521
+ type: 5,
522
+ };
523
+ }
524
+ throw new Error('Invalid socks5 proxy format');
525
+ };
526
+ exports.parseSocksProxy = parseSocksProxy;
package/dist/app.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Standalone CLI / Docker entry point.
4
+ *
5
+ * Reads configuration from environment variables and command-line arguments,
6
+ * then starts the proxy server. No MWC-specific code lives here.
7
+ *
8
+ * Supported env vars:
9
+ * PORT — listen port (default 2344, overridden by argv[2])
10
+ * URL_ROOT — API path prefix (default /api/vm/net)
11
+ * ALLOW_ORIGIN — CORS origin header value (default *)
12
+ * MAX_CONNECTIONS_PER_IP — per-IP connection cap (default 5)
13
+ * ACCESS_CODE — secret for /connections endpoint
14
+ * SIGNAL_SERVER_URL — signal server URL (default https://signal.mcraft.fun)
15
+ * SIGNAL_DESCRIPTION — description forwarded to signal server
16
+ * SIGNAL_DOMAIN — domain forwarded to signal server
17
+ * DISABLE_SIGNAL — set to 1 or true to disable signal server reporting
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;GAgBG"}
package/dist/app.js ADDED
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Standalone CLI / Docker entry point.
5
+ *
6
+ * Reads configuration from environment variables and command-line arguments,
7
+ * then starts the proxy server. No MWC-specific code lives here.
8
+ *
9
+ * Supported env vars:
10
+ * PORT — listen port (default 2344, overridden by argv[2])
11
+ * URL_ROOT — API path prefix (default /api/vm/net)
12
+ * ALLOW_ORIGIN — CORS origin header value (default *)
13
+ * MAX_CONNECTIONS_PER_IP — per-IP connection cap (default 5)
14
+ * ACCESS_CODE — secret for /connections endpoint
15
+ * SIGNAL_SERVER_URL — signal server URL (default https://signal.mcraft.fun)
16
+ * SIGNAL_DESCRIPTION — description forwarded to signal server
17
+ * SIGNAL_DOMAIN — domain forwarded to signal server
18
+ * DISABLE_SIGNAL — set to 1 or true to disable signal server reporting
19
+ */
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ const path_1 = __importDefault(require("path"));
25
+ const https_1 = __importDefault(require("https"));
26
+ const fs_1 = __importDefault(require("fs"));
27
+ const express_1 = __importDefault(require("express"));
28
+ const compression_1 = __importDefault(require("compression"));
29
+ const index_1 = require("./index");
30
+ if (fs_1.default.existsSync(path_1.default.join(__dirname, './env.js'))) {
31
+ require('./env.js');
32
+ }
33
+ const app = (0, express_1.default)();
34
+ const keyFile = path_1.default.join(__dirname, './key.pem');
35
+ let httpsServer;
36
+ if (fs_1.default.existsSync(keyFile)) {
37
+ const key = fs_1.default.readFileSync(keyFile);
38
+ const cert = fs_1.default.readFileSync(path_1.default.join(__dirname, './cert.pem'));
39
+ httpsServer = https_1.default.createServer({ key, cert }, app);
40
+ }
41
+ app.use((0, compression_1.default)());
42
+ const logsDir = path_1.default.join(__dirname, 'logs');
43
+ fs_1.default.mkdirSync(logsDir, { recursive: true });
44
+ const accessFile = fs_1.default.createWriteStream(path_1.default.join(logsDir, 'access.log'), { flags: 'a' });
45
+ const urlRoot = process.env.URL_ROOT ?? '/api/vm/net';
46
+ const portArg = process.argv.indexOf('--port');
47
+ const port = process.argv[2] && !process.argv[2].startsWith('-')
48
+ ? process.argv[2]
49
+ : portArg === -1
50
+ ? process.env.PORT ?? 2344
51
+ : process.argv[portArg + 1];
52
+ app.use((0, index_1.createProxyMiddleware)({
53
+ allowOrigin: process.env.ALLOW_ORIGIN ?? '*',
54
+ server: httpsServer,
55
+ urlRoot,
56
+ log(line) {
57
+ const ts = new Date().toISOString().replace('T', ' ').split('.')[0];
58
+ accessFile.write(`[${ts}] ${line}\n`);
59
+ },
60
+ allowOriginApp: true,
61
+ maxConnectionsPerIp: process.env.MAX_CONNECTIONS_PER_IP ? Number(process.env.MAX_CONNECTIONS_PER_IP) : 5,
62
+ signal: process.env.DISABLE_SIGNAL === '1' || process.env.DISABLE_SIGNAL?.toLowerCase() === 'true'
63
+ ? undefined
64
+ : {
65
+ serverUrl: process.env.SIGNAL_SERVER_URL ?? 'https://signal.mcraft.fun',
66
+ description: process.env.SIGNAL_DESCRIPTION,
67
+ domain: process.env.SIGNAL_DOMAIN,
68
+ listenPort: Number(port),
69
+ },
70
+ }));
71
+ app.use(express_1.default.static(path_1.default.join(__dirname, './dist')));
72
+ (httpsServer ?? app).listen(port, () => {
73
+ console.log(`Proxy server listening on port ${port}`);
74
+ setInterval(() => { });
75
+ });
@@ -0,0 +1,5 @@
1
+ import { type Express } from 'express';
2
+ import type { ProxyMiddlewareOptions } from './api';
3
+ declare const _default: (app: Express, authTokensEndpoint?: string, sessionServerProxy?: string, authLog?: (str: string) => void, urlRoot?: string, options?: ProxyMiddlewareOptions) => void;
4
+ export default _default;
5
+ //# sourceMappingURL=authEndpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authEndpoint.d.ts","sourceRoot":"","sources":["../src/authEndpoint.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAA;AAKtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,OAAO,CAAA;yBAoCnC,KAAK,OAAO,EAAE,2BAAwB,EAAE,2BAA+B,EAAE,WAAW,KAAK,MAAM,SAAO,EAAE,gBAAY,EAAE,UAAS,sBAA2B;AAA1K,wBA4KC"}