@rubytech/create-realagent 1.0.678 → 1.0.681
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/index.js +232 -39
- package/package.json +1 -1
- package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.d.ts +2 -0
- package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.d.ts.map +1 -0
- package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.js +112 -0
- package/payload/platform/lib/graph-mcp/dist/__tests__/cypher-validate.test.js.map +1 -0
- package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.d.ts +2 -0
- package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.d.ts.map +1 -0
- package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.js +163 -0
- package/payload/platform/lib/graph-mcp/dist/__tests__/schema-cache.test.js.map +1 -0
- package/payload/platform/lib/graph-mcp/dist/cypher-validate.d.ts +38 -0
- package/payload/platform/lib/graph-mcp/dist/cypher-validate.d.ts.map +1 -0
- package/payload/platform/lib/graph-mcp/dist/cypher-validate.js +130 -0
- package/payload/platform/lib/graph-mcp/dist/cypher-validate.js.map +1 -0
- package/payload/platform/lib/graph-mcp/dist/index.js +201 -45
- package/payload/platform/lib/graph-mcp/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts +78 -0
- package/payload/platform/lib/graph-mcp/dist/schema-cache.d.ts.map +1 -0
- package/payload/platform/lib/graph-mcp/dist/schema-cache.js +194 -0
- package/payload/platform/lib/graph-mcp/dist/schema-cache.js.map +1 -0
- package/payload/platform/lib/graph-mcp/src/__tests__/cypher-validate.test.ts +141 -0
- package/payload/platform/lib/graph-mcp/src/__tests__/schema-cache.test.ts +169 -0
- package/payload/platform/lib/graph-mcp/src/cypher-validate.ts +157 -0
- package/payload/platform/lib/graph-mcp/src/index.ts +247 -47
- package/payload/platform/lib/graph-mcp/src/schema-cache.ts +212 -0
- package/payload/platform/lib/graph-trash/dist/index.d.ts +8 -0
- package/payload/platform/lib/graph-trash/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-trash/dist/index.js +109 -14
- package/payload/platform/lib/graph-trash/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-trash/src/index.ts +136 -21
- package/payload/platform/plugins/docs/references/deployment.md +4 -2
- package/payload/platform/plugins/docs/references/memory-guide.md +5 -1
- package/payload/platform/plugins/docs/references/platform.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +20 -0
- package/payload/platform/plugins/memory/PLUGIN.md +1 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +54 -6
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.d.ts +36 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.js +86 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/filter-token.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts +23 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js +47 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-delete.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts +58 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js +125 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-find-candidates.js.map +1 -0
- package/payload/platform/scripts/vnc.sh +12 -409
- package/payload/platform/templates/agents/admin/IDENTITY.md +16 -0
- package/payload/platform/templates/dotfiles/.tmux.conf +1 -0
- package/payload/platform/templates/systemd/maxy-ttyd.service +25 -0
- package/payload/server/chunk-3RBKKDHC.js +783 -0
- package/payload/server/maxy-edge.js +377 -8
- package/payload/server/public/assets/admin-CIkyOur7.js +362 -0
- package/payload/server/public/assets/admin-kHJ-D0s7.css +1 -0
- package/payload/server/public/index.html +2 -1
- package/payload/server/server.js +391 -412
- package/payload/server/public/assets/admin-BBL1no_g.js +0 -352
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
+
LOG_DIR,
|
|
2
3
|
canAccessAdmin,
|
|
4
|
+
describeRemoteSession,
|
|
3
5
|
newCorrId,
|
|
6
|
+
parseCookieValue,
|
|
4
7
|
sanitizeClientCorrId,
|
|
5
8
|
vncLog
|
|
6
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3RBKKDHC.js";
|
|
7
10
|
|
|
8
11
|
// server/maxy-edge.ts
|
|
9
12
|
import { createServer, request as httpRequest } from "http";
|
|
10
|
-
import { createConnection as
|
|
13
|
+
import { createConnection as createConnection3 } from "net";
|
|
11
14
|
import { readFileSync, existsSync, watchFile } from "fs";
|
|
12
15
|
import { homedir } from "os";
|
|
13
16
|
import { join } from "path";
|
|
@@ -61,15 +64,18 @@ function handleUpgrade(req, clientSocket, head, opts) {
|
|
|
61
64
|
const originHeader = headerString(req.headers.origin);
|
|
62
65
|
const remote = req.socket.remoteAddress;
|
|
63
66
|
const xff = headerString(req.headers["x-forwarded-for"]);
|
|
67
|
+
const cookieHeader = headerString(req.headers.cookie);
|
|
64
68
|
const decision = canAccessAdmin({
|
|
65
69
|
host: hostHeader,
|
|
66
70
|
remoteAddress: remote,
|
|
67
71
|
xForwardedFor: xff,
|
|
68
|
-
cookieHeader
|
|
72
|
+
cookieHeader,
|
|
69
73
|
isPublicHost: opts.isPublicHost
|
|
70
74
|
});
|
|
71
75
|
if (!decision.allow) {
|
|
72
76
|
const status = decision.reason === "public-host" ? 404 : 401;
|
|
77
|
+
const rawToken = parseCookieValue(cookieHeader, "__remote_session");
|
|
78
|
+
const tokenInfo = describeRemoteSession(rawToken);
|
|
73
79
|
vncLog("ws-upgrade", {
|
|
74
80
|
corrId,
|
|
75
81
|
clientCorrId: clientCorrId ?? null,
|
|
@@ -78,7 +84,10 @@ function handleUpgrade(req, clientSocket, head, opts) {
|
|
|
78
84
|
ip: remote,
|
|
79
85
|
xff: xff ?? null,
|
|
80
86
|
origin: originHeader ?? null,
|
|
81
|
-
host: hostHeader
|
|
87
|
+
host: hostHeader,
|
|
88
|
+
cookieHeaderPresent: cookieHeader != null && cookieHeader.length > 0,
|
|
89
|
+
tokenPresent: tokenInfo.present,
|
|
90
|
+
tokenExpired: tokenInfo.expired
|
|
82
91
|
});
|
|
83
92
|
writeStatusAndDestroy(clientSocket, status, decision.reason === "public-host" ? "Not Found" : "Unauthorized");
|
|
84
93
|
return;
|
|
@@ -267,6 +276,357 @@ Content-Length: 0\r
|
|
|
267
276
|
socket.destroy();
|
|
268
277
|
}
|
|
269
278
|
|
|
279
|
+
// server/ws-proxy-ttyd.ts
|
|
280
|
+
import { createConnection as createConnection2 } from "net";
|
|
281
|
+
|
|
282
|
+
// app/lib/ttyd-logger.ts
|
|
283
|
+
import { appendFileSync, mkdirSync } from "fs";
|
|
284
|
+
import { resolve } from "path";
|
|
285
|
+
var EDGE_LOG_FILE = resolve(LOG_DIR, "edge-boot.log");
|
|
286
|
+
try {
|
|
287
|
+
mkdirSync(LOG_DIR, { recursive: true });
|
|
288
|
+
} catch (err) {
|
|
289
|
+
console.error(`[ttyd-log-fail] mkdir ${LOG_DIR} failed: ${err.message}`);
|
|
290
|
+
}
|
|
291
|
+
function ttydLog(phase, fields = {}) {
|
|
292
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
293
|
+
const kv = Object.entries(fields).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(" ");
|
|
294
|
+
const line = kv.length > 0 ? `[${ts}] [${phase}] ${kv}
|
|
295
|
+
` : `[${ts}] [${phase}]
|
|
296
|
+
`;
|
|
297
|
+
try {
|
|
298
|
+
appendFileSync(EDGE_LOG_FILE, line);
|
|
299
|
+
} catch (err) {
|
|
300
|
+
console.error(`[ttyd-log-fail] ${err.message} \u2014 dropped: ${line.slice(0, 300).trim()}`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// server/ws-proxy-ttyd.ts
|
|
305
|
+
var WS_PATH2 = "/ttyd";
|
|
306
|
+
var UPSTREAM_TIMEOUT_MS2 = 5e3;
|
|
307
|
+
var FLOW_ACTIVE_INTERVAL_MS = 5e3;
|
|
308
|
+
var FLOW_IDLE_INTERVAL_MS = 3e4;
|
|
309
|
+
var CHUNK_THROTTLE_MS = 1e3;
|
|
310
|
+
var CHUNK_UNTHROTTLED_COUNT = 5;
|
|
311
|
+
var HOP_BY_HOP2 = /* @__PURE__ */ new Set([
|
|
312
|
+
"connection",
|
|
313
|
+
"keep-alive",
|
|
314
|
+
"proxy-authenticate",
|
|
315
|
+
"proxy-authorization",
|
|
316
|
+
"te",
|
|
317
|
+
"trailer",
|
|
318
|
+
"transfer-encoding",
|
|
319
|
+
"upgrade"
|
|
320
|
+
]);
|
|
321
|
+
function attachTtydWsProxy(server2, opts) {
|
|
322
|
+
const upstreamHost = opts.upstreamHost ?? "127.0.0.1";
|
|
323
|
+
const upstreamPort = opts.upstreamPort ?? 7681;
|
|
324
|
+
const now = opts.now ?? (() => Date.now());
|
|
325
|
+
server2.on("upgrade", (req, clientSocket, head) => {
|
|
326
|
+
try {
|
|
327
|
+
handleUpgrade2(req, clientSocket, head, {
|
|
328
|
+
isPublicHost: opts.isPublicHost,
|
|
329
|
+
upstreamHost,
|
|
330
|
+
upstreamPort,
|
|
331
|
+
now
|
|
332
|
+
});
|
|
333
|
+
} catch (err) {
|
|
334
|
+
ttydLog("ttyd-ws-upgrade", {
|
|
335
|
+
decision: "rejected",
|
|
336
|
+
reason: "handler-exception",
|
|
337
|
+
err: err.message
|
|
338
|
+
});
|
|
339
|
+
clientSocket.destroy();
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
function handleUpgrade2(req, clientSocket, head, opts) {
|
|
344
|
+
const url = req.url ?? "";
|
|
345
|
+
const qsIndex = url.indexOf("?");
|
|
346
|
+
const pathname = qsIndex === -1 ? url : url.slice(0, qsIndex);
|
|
347
|
+
if (pathname !== WS_PATH2) return;
|
|
348
|
+
const corrId = newCorrId();
|
|
349
|
+
const query = qsIndex === -1 ? "" : url.slice(qsIndex + 1);
|
|
350
|
+
const clientCorrId = sanitizeClientCorrId(parseQueryParam2(query, "corrId"));
|
|
351
|
+
const hostHeader = (req.headers.host ?? "").split(":")[0];
|
|
352
|
+
const originHeader = headerString2(req.headers.origin);
|
|
353
|
+
const remote = req.socket.remoteAddress;
|
|
354
|
+
const xff = headerString2(req.headers["x-forwarded-for"]);
|
|
355
|
+
const cookieHeader = headerString2(req.headers.cookie);
|
|
356
|
+
const decision = canAccessAdmin({
|
|
357
|
+
host: hostHeader,
|
|
358
|
+
remoteAddress: remote,
|
|
359
|
+
xForwardedFor: xff,
|
|
360
|
+
cookieHeader,
|
|
361
|
+
isPublicHost: opts.isPublicHost
|
|
362
|
+
});
|
|
363
|
+
if (!decision.allow) {
|
|
364
|
+
const status = decision.reason === "public-host" ? 404 : 401;
|
|
365
|
+
const rawToken = parseCookieValue(cookieHeader, "__remote_session");
|
|
366
|
+
const tokenInfo = describeRemoteSession(rawToken);
|
|
367
|
+
ttydLog("ttyd-ws-upgrade", {
|
|
368
|
+
corrId,
|
|
369
|
+
clientCorrId: clientCorrId ?? null,
|
|
370
|
+
decision: "rejected",
|
|
371
|
+
reason: decision.reason,
|
|
372
|
+
ip: remote,
|
|
373
|
+
xff: xff ?? null,
|
|
374
|
+
origin: originHeader ?? null,
|
|
375
|
+
host: hostHeader,
|
|
376
|
+
cookieHeaderPresent: cookieHeader != null && cookieHeader.length > 0,
|
|
377
|
+
tokenPresent: tokenInfo.present,
|
|
378
|
+
tokenExpired: tokenInfo.expired
|
|
379
|
+
});
|
|
380
|
+
writeStatusAndDestroy2(clientSocket, status, decision.reason === "public-host" ? "Not Found" : "Unauthorized");
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const originHost = parseOriginHost2(originHeader);
|
|
384
|
+
if (!originHost) {
|
|
385
|
+
ttydLog("ttyd-ws-upgrade", {
|
|
386
|
+
corrId,
|
|
387
|
+
clientCorrId: clientCorrId ?? null,
|
|
388
|
+
decision: "rejected",
|
|
389
|
+
reason: "origin-missing-or-invalid",
|
|
390
|
+
origin: originHeader ?? null,
|
|
391
|
+
host: hostHeader,
|
|
392
|
+
ip: remote
|
|
393
|
+
});
|
|
394
|
+
writeStatusAndDestroy2(clientSocket, 403, "Forbidden");
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
if (originHost !== hostHeader) {
|
|
398
|
+
ttydLog("ttyd-ws-upgrade", {
|
|
399
|
+
corrId,
|
|
400
|
+
clientCorrId: clientCorrId ?? null,
|
|
401
|
+
decision: "rejected",
|
|
402
|
+
reason: "origin-mismatch",
|
|
403
|
+
origin_host: originHost,
|
|
404
|
+
host: hostHeader,
|
|
405
|
+
ip: remote
|
|
406
|
+
});
|
|
407
|
+
writeStatusAndDestroy2(clientSocket, 403, "Forbidden");
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
if (opts.isPublicHost(originHost)) {
|
|
411
|
+
ttydLog("ttyd-ws-upgrade", {
|
|
412
|
+
corrId,
|
|
413
|
+
clientCorrId: clientCorrId ?? null,
|
|
414
|
+
decision: "rejected",
|
|
415
|
+
reason: "origin-public-host",
|
|
416
|
+
origin_host: originHost,
|
|
417
|
+
host: hostHeader,
|
|
418
|
+
ip: remote
|
|
419
|
+
});
|
|
420
|
+
writeStatusAndDestroy2(clientSocket, 403, "Forbidden");
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
ttydLog("ttyd-ws-upgrade", {
|
|
424
|
+
corrId,
|
|
425
|
+
clientCorrId: clientCorrId ?? null,
|
|
426
|
+
decision: "accepted",
|
|
427
|
+
ip: remote,
|
|
428
|
+
xff: xff ?? null,
|
|
429
|
+
origin: originHeader ?? null,
|
|
430
|
+
host: hostHeader,
|
|
431
|
+
sec_ws_version: headerString2(req.headers["sec-websocket-version"]) ?? null,
|
|
432
|
+
sec_ws_protocol: headerString2(req.headers["sec-websocket-protocol"]) ?? null
|
|
433
|
+
});
|
|
434
|
+
const connectStart = opts.now();
|
|
435
|
+
const upstream = createConnection2({ host: opts.upstreamHost, port: opts.upstreamPort });
|
|
436
|
+
upstream.setTimeout(UPSTREAM_TIMEOUT_MS2);
|
|
437
|
+
let bytesClientToUpstream = 0;
|
|
438
|
+
let bytesUpstreamToClient = 0;
|
|
439
|
+
let lastFlowBytesClient = 0;
|
|
440
|
+
let lastFlowBytesUpstream = 0;
|
|
441
|
+
let lastActivityAt = opts.now();
|
|
442
|
+
let lastChunkLogAtClient = 0;
|
|
443
|
+
let lastChunkLogAtUpstream = 0;
|
|
444
|
+
let chunkCountClient = 0;
|
|
445
|
+
let chunkCountUpstream = 0;
|
|
446
|
+
let closedBy = null;
|
|
447
|
+
let proxyOpened = false;
|
|
448
|
+
const sessionStart = opts.now();
|
|
449
|
+
let flowHandle = null;
|
|
450
|
+
let currentFlowInterval = FLOW_ACTIVE_INTERVAL_MS;
|
|
451
|
+
const scheduleFlow = (intervalMs) => {
|
|
452
|
+
if (flowHandle) clearInterval(flowHandle);
|
|
453
|
+
currentFlowInterval = intervalMs;
|
|
454
|
+
flowHandle = setInterval(emitFlow, intervalMs);
|
|
455
|
+
};
|
|
456
|
+
const emitFlow = () => {
|
|
457
|
+
if (!proxyOpened || closedBy) return;
|
|
458
|
+
const deltaClient = bytesClientToUpstream - lastFlowBytesClient;
|
|
459
|
+
const deltaUpstream = bytesUpstreamToClient - lastFlowBytesUpstream;
|
|
460
|
+
lastFlowBytesClient = bytesClientToUpstream;
|
|
461
|
+
lastFlowBytesUpstream = bytesUpstreamToClient;
|
|
462
|
+
const idleMs = opts.now() - lastActivityAt;
|
|
463
|
+
ttydLog("ttyd-proxy-flow", {
|
|
464
|
+
corrId,
|
|
465
|
+
clientBytes: bytesClientToUpstream,
|
|
466
|
+
upstreamBytes: bytesUpstreamToClient,
|
|
467
|
+
clientBytesDelta: deltaClient,
|
|
468
|
+
upstreamBytesDelta: deltaUpstream,
|
|
469
|
+
idleMs
|
|
470
|
+
});
|
|
471
|
+
const active = deltaClient > 0 || deltaUpstream > 0;
|
|
472
|
+
const desiredInterval = active ? FLOW_ACTIVE_INTERVAL_MS : FLOW_IDLE_INTERVAL_MS;
|
|
473
|
+
if (desiredInterval !== currentFlowInterval) scheduleFlow(desiredInterval);
|
|
474
|
+
};
|
|
475
|
+
const finish = (side, reason) => {
|
|
476
|
+
if (closedBy) return;
|
|
477
|
+
closedBy = side;
|
|
478
|
+
if (flowHandle) {
|
|
479
|
+
clearInterval(flowHandle);
|
|
480
|
+
flowHandle = null;
|
|
481
|
+
}
|
|
482
|
+
if (proxyOpened) {
|
|
483
|
+
ttydLog("ttyd-proxy-close", {
|
|
484
|
+
corrId,
|
|
485
|
+
closedBy: side,
|
|
486
|
+
reason,
|
|
487
|
+
clientBytes: bytesClientToUpstream,
|
|
488
|
+
upstreamBytes: bytesUpstreamToClient,
|
|
489
|
+
durationMs: opts.now() - sessionStart
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
clientSocket.destroy();
|
|
493
|
+
upstream.destroy();
|
|
494
|
+
};
|
|
495
|
+
upstream.once("connect", () => {
|
|
496
|
+
upstream.setTimeout(0);
|
|
497
|
+
proxyOpened = true;
|
|
498
|
+
ttydLog("ttyd-proxy-open", {
|
|
499
|
+
corrId,
|
|
500
|
+
upstream: `${opts.upstreamHost}:${opts.upstreamPort}`,
|
|
501
|
+
connect_ms: opts.now() - connectStart
|
|
502
|
+
});
|
|
503
|
+
const lines = [];
|
|
504
|
+
lines.push(`${req.method ?? "GET"} ${WS_PATH2} HTTP/${req.httpVersion}`);
|
|
505
|
+
lines.push(`host: ${opts.upstreamHost}:${opts.upstreamPort}`);
|
|
506
|
+
for (const [name, value] of Object.entries(req.headers)) {
|
|
507
|
+
if (name === "host") continue;
|
|
508
|
+
if (HOP_BY_HOP2.has(name)) continue;
|
|
509
|
+
if (value == null) continue;
|
|
510
|
+
if (Array.isArray(value)) {
|
|
511
|
+
for (const v of value) lines.push(`${name}: ${v}`);
|
|
512
|
+
} else {
|
|
513
|
+
lines.push(`${name}: ${value}`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
const upgradeHeader = headerString2(req.headers.upgrade);
|
|
517
|
+
const connectionHeader = headerString2(req.headers.connection);
|
|
518
|
+
if (upgradeHeader) lines.push(`upgrade: ${upgradeHeader}`);
|
|
519
|
+
if (connectionHeader) lines.push(`connection: ${connectionHeader}`);
|
|
520
|
+
upstream.write(lines.join("\r\n") + "\r\n\r\n");
|
|
521
|
+
if (head && head.length > 0) upstream.write(head);
|
|
522
|
+
const logChunk = (dir, bytes) => {
|
|
523
|
+
const now = opts.now();
|
|
524
|
+
if (dir === "client\u2192upstream") {
|
|
525
|
+
chunkCountClient += 1;
|
|
526
|
+
const sinceLastMs = lastChunkLogAtClient === 0 ? 0 : now - lastChunkLogAtClient;
|
|
527
|
+
if (chunkCountClient <= CHUNK_UNTHROTTLED_COUNT || sinceLastMs >= CHUNK_THROTTLE_MS) {
|
|
528
|
+
ttydLog("ttyd-proxy-chunk", { corrId, dir, bytes, sinceLastMs });
|
|
529
|
+
lastChunkLogAtClient = now;
|
|
530
|
+
}
|
|
531
|
+
} else {
|
|
532
|
+
chunkCountUpstream += 1;
|
|
533
|
+
const sinceLastMs = lastChunkLogAtUpstream === 0 ? 0 : now - lastChunkLogAtUpstream;
|
|
534
|
+
if (chunkCountUpstream <= CHUNK_UNTHROTTLED_COUNT || sinceLastMs >= CHUNK_THROTTLE_MS) {
|
|
535
|
+
ttydLog("ttyd-proxy-chunk", { corrId, dir, bytes, sinceLastMs });
|
|
536
|
+
lastChunkLogAtUpstream = now;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
lastActivityAt = now;
|
|
540
|
+
};
|
|
541
|
+
clientSocket.on("data", (chunk) => {
|
|
542
|
+
bytesClientToUpstream += chunk.length;
|
|
543
|
+
logChunk("client\u2192upstream", chunk.length);
|
|
544
|
+
});
|
|
545
|
+
upstream.on("data", (chunk) => {
|
|
546
|
+
bytesUpstreamToClient += chunk.length;
|
|
547
|
+
logChunk("upstream\u2192client", chunk.length);
|
|
548
|
+
});
|
|
549
|
+
clientSocket.pipe(upstream);
|
|
550
|
+
upstream.pipe(clientSocket);
|
|
551
|
+
scheduleFlow(FLOW_ACTIVE_INTERVAL_MS);
|
|
552
|
+
clientSocket.once("close", (hadError) => {
|
|
553
|
+
finish("client", hadError ? "error" : "normal");
|
|
554
|
+
});
|
|
555
|
+
upstream.once("close", (hadError) => {
|
|
556
|
+
finish("upstream", hadError ? "error" : "normal");
|
|
557
|
+
});
|
|
558
|
+
clientSocket.once("error", (err) => {
|
|
559
|
+
ttydLog("ttyd-proxy-error", { corrId, side: "client", err: err.message });
|
|
560
|
+
finish("client", "error");
|
|
561
|
+
});
|
|
562
|
+
upstream.once("error", (err) => {
|
|
563
|
+
ttydLog("ttyd-proxy-error", { corrId, side: "upstream", err: err.message });
|
|
564
|
+
finish("upstream", "error");
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
upstream.once("timeout", () => {
|
|
568
|
+
if (proxyOpened) return;
|
|
569
|
+
ttydLog("ttyd-proxy-error", {
|
|
570
|
+
corrId,
|
|
571
|
+
side: "upstream-connect",
|
|
572
|
+
err: "timeout",
|
|
573
|
+
timeout_ms: UPSTREAM_TIMEOUT_MS2
|
|
574
|
+
});
|
|
575
|
+
writeStatusAndDestroy2(clientSocket, 504, "Gateway Timeout");
|
|
576
|
+
upstream.destroy();
|
|
577
|
+
});
|
|
578
|
+
upstream.once("error", (err) => {
|
|
579
|
+
if (proxyOpened) return;
|
|
580
|
+
ttydLog("ttyd-proxy-error", {
|
|
581
|
+
corrId,
|
|
582
|
+
side: "upstream-connect",
|
|
583
|
+
err: err.message
|
|
584
|
+
});
|
|
585
|
+
writeStatusAndDestroy2(clientSocket, 502, "Bad Gateway");
|
|
586
|
+
upstream.destroy();
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
function parseQueryParam2(query, key) {
|
|
590
|
+
if (!query) return null;
|
|
591
|
+
for (const pair of query.split("&")) {
|
|
592
|
+
const eq = pair.indexOf("=");
|
|
593
|
+
const k = eq === -1 ? pair : pair.slice(0, eq);
|
|
594
|
+
if (k !== key) continue;
|
|
595
|
+
const v = eq === -1 ? "" : pair.slice(eq + 1);
|
|
596
|
+
try {
|
|
597
|
+
return decodeURIComponent(v);
|
|
598
|
+
} catch {
|
|
599
|
+
return null;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
function headerString2(value) {
|
|
605
|
+
if (value == null) return void 0;
|
|
606
|
+
return Array.isArray(value) ? value[0] : value;
|
|
607
|
+
}
|
|
608
|
+
function parseOriginHost2(origin) {
|
|
609
|
+
if (!origin) return null;
|
|
610
|
+
try {
|
|
611
|
+
return new URL(origin).hostname;
|
|
612
|
+
} catch {
|
|
613
|
+
return null;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
function writeStatusAndDestroy2(socket, status, statusText) {
|
|
617
|
+
try {
|
|
618
|
+
socket.write(
|
|
619
|
+
`HTTP/1.1 ${status} ${statusText}\r
|
|
620
|
+
Connection: close\r
|
|
621
|
+
Content-Length: 0\r
|
|
622
|
+
\r
|
|
623
|
+
`
|
|
624
|
+
);
|
|
625
|
+
} catch {
|
|
626
|
+
}
|
|
627
|
+
socket.destroy();
|
|
628
|
+
}
|
|
629
|
+
|
|
270
630
|
// server/maxy-edge.ts
|
|
271
631
|
var PLATFORM_ROOT = process.env.MAXY_PLATFORM_ROOT || "";
|
|
272
632
|
var BRAND_JSON_PATH = PLATFORM_ROOT ? join(PLATFORM_ROOT, "config", "brand.json") : "";
|
|
@@ -304,7 +664,9 @@ var UPSTREAM_HOST = process.env.MAXY_UI_HOST ?? "127.0.0.1";
|
|
|
304
664
|
var UPSTREAM_PORT = parseInt(process.env.MAXY_UI_PORT ?? "19199", 10);
|
|
305
665
|
var WEBSOCKIFY_HOST = process.env.WEBSOCKIFY_HOST ?? "127.0.0.1";
|
|
306
666
|
var WEBSOCKIFY_PORT = parseInt(process.env.WEBSOCKIFY_PORT ?? "6080", 10);
|
|
307
|
-
var
|
|
667
|
+
var TTYD_HOST = process.env.TTYD_HOST ?? "127.0.0.1";
|
|
668
|
+
var TTYD_PORT = parseInt(process.env.TTYD_PORT ?? "7681", 10);
|
|
669
|
+
var HOP_BY_HOP3 = /* @__PURE__ */ new Set([
|
|
308
670
|
"connection",
|
|
309
671
|
"keep-alive",
|
|
310
672
|
"proxy-authenticate",
|
|
@@ -318,7 +680,7 @@ function forwardHttp(clientReq, clientRes) {
|
|
|
318
680
|
const headers = {};
|
|
319
681
|
for (const [name, value] of Object.entries(clientReq.headers)) {
|
|
320
682
|
if (value == null) continue;
|
|
321
|
-
if (
|
|
683
|
+
if (HOP_BY_HOP3.has(name)) continue;
|
|
322
684
|
headers[name] = value;
|
|
323
685
|
}
|
|
324
686
|
const existingXff = headers["x-forwarded-for"];
|
|
@@ -348,7 +710,7 @@ function forwardHttp(clientReq, clientRes) {
|
|
|
348
710
|
clientReq.pipe(upstream);
|
|
349
711
|
}
|
|
350
712
|
function forwardUpgrade(req, clientSocket, head) {
|
|
351
|
-
const upstream =
|
|
713
|
+
const upstream = createConnection3({ host: UPSTREAM_HOST, port: UPSTREAM_PORT });
|
|
352
714
|
upstream.setTimeout(5e3);
|
|
353
715
|
upstream.once("connect", () => {
|
|
354
716
|
upstream.setTimeout(0);
|
|
@@ -357,7 +719,7 @@ function forwardUpgrade(req, clientSocket, head) {
|
|
|
357
719
|
lines.push(`host: ${UPSTREAM_HOST}:${UPSTREAM_PORT}`);
|
|
358
720
|
for (const [name, value] of Object.entries(req.headers)) {
|
|
359
721
|
if (name === "host") continue;
|
|
360
|
-
if (
|
|
722
|
+
if (HOP_BY_HOP3.has(name)) continue;
|
|
361
723
|
if (value == null) continue;
|
|
362
724
|
if (Array.isArray(value)) {
|
|
363
725
|
for (const v of value) lines.push(`${name}: ${v}`);
|
|
@@ -408,15 +770,22 @@ attachVncWsProxy(server, {
|
|
|
408
770
|
upstreamHost: WEBSOCKIFY_HOST,
|
|
409
771
|
upstreamPort: WEBSOCKIFY_PORT
|
|
410
772
|
});
|
|
773
|
+
attachTtydWsProxy(server, {
|
|
774
|
+
isPublicHost,
|
|
775
|
+
upstreamHost: TTYD_HOST,
|
|
776
|
+
upstreamPort: TTYD_PORT
|
|
777
|
+
});
|
|
411
778
|
server.on("upgrade", (req, socket, head) => {
|
|
412
779
|
const url = req.url ?? "";
|
|
413
780
|
const qsIndex = url.indexOf("?");
|
|
414
781
|
const pathname = qsIndex === -1 ? url : url.slice(0, qsIndex);
|
|
415
782
|
if (pathname === "/websockify") return;
|
|
783
|
+
if (pathname === "/ttyd") return;
|
|
416
784
|
forwardUpgrade(req, socket, head);
|
|
417
785
|
});
|
|
418
786
|
server.listen(EDGE_PORT, EDGE_HOSTNAME, () => {
|
|
419
787
|
console.log(`[edge] listening on http://${EDGE_HOSTNAME}:${EDGE_PORT}`);
|
|
420
788
|
console.log(`[edge] /websockify \u2192 ${WEBSOCKIFY_HOST}:${WEBSOCKIFY_PORT}`);
|
|
789
|
+
console.log(`[edge] /ttyd \u2192 ${TTYD_HOST}:${TTYD_PORT}`);
|
|
421
790
|
console.log(`[edge] everything else \u2192 ${UPSTREAM_HOST}:${UPSTREAM_PORT}`);
|
|
422
791
|
});
|