Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemathinc
GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/hub/proxy/index.ts
5805 views
1
/*
2
* This file is part of CoCalc: Copyright © 2020-2025 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
import {
7
Application,
8
type NextFunction,
9
type Request,
10
type Response,
11
} from "express";
12
13
import getLogger from "@cocalc/hub/logger";
14
import base_path from "@cocalc/backend/base-path";
15
16
import initRequest from "./handle-request";
17
import initUpgrade from "./handle-upgrade";
18
19
const logger = getLogger("proxy");
20
21
import type { Server } from "node:http";
22
import type { ProjectControlFunction } from "@cocalc/server/projects/control";
23
interface Options {
24
app: Application;
25
httpServer: Server; // got from express_app via httpServer = http.createServer(app).
26
projectControl: ProjectControlFunction; // controls projects (aka "compute server")
27
isPersonal: boolean; // if true, disables all access controls
28
proxyConat: boolean;
29
}
30
31
// UUID regex pattern for project ID validation
32
const UUID_PATTERN =
33
"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}";
34
const UUID_REGEX = new RegExp(`^${UUID_PATTERN}$`);
35
36
/**
37
* Middleware to validate that the project_id route parameter is a valid UUID.
38
* If valid, continues to next middleware. If invalid, skips to next route.
39
*/
40
function uuidMiddleware(
41
req: Request<{ project_id: string }>,
42
_res: Response,
43
next: NextFunction,
44
) {
45
if (UUID_REGEX.test(req.params.project_id)) {
46
return next();
47
}
48
// Not a valid project ID UUID: skip to next route
49
return next("route");
50
}
51
52
export default function initProxy(opts: Options) {
53
const prefix = base_path.length <= 1 ? "" : base_path;
54
const routePath = `${prefix}/:project_id/{*splat}`;
55
logger.info("creating proxy server with route pattern", routePath);
56
57
// tcp connections:
58
const handleProxy = initRequest(opts);
59
60
// Create regex for upgrade handler (still needed for WebSocket matching)
61
const proxy_regexp = `^${prefix}\/${UUID_PATTERN}\/.*`;
62
63
// websocket upgrades:
64
const handleUpgrade = initUpgrade(opts, proxy_regexp);
65
66
// Use Express 5 path syntax with UUID validation middleware
67
opts.app.all(routePath, uuidMiddleware, handleProxy);
68
69
opts.httpServer.on("upgrade", handleUpgrade);
70
}
71
72