CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/next/lib/share/virtual-hosts.ts
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
Support for virtual hosts.
8
*/
9
10
import type { Request, Response } from "express";
11
12
import basePath from "@cocalc/backend/base-path";
13
import { getLogger } from "@cocalc/backend/logger";
14
import isAuthenticated from "./authenticate";
15
import getVirtualHostInfo from "./get-vhost-info";
16
import { staticHandler } from "./handle-raw";
17
import pathToFiles from "./path-to-files";
18
19
const logger = getLogger("virtual-hosts");
20
21
export default function virtualHostsMiddleware() {
22
// we return the middleware to match the standard pattern for express,
23
// and give more flexibility.
24
return async function (
25
req: Request,
26
res: Response,
27
next: Function,
28
): Promise<void> {
29
// For debugging in cc-in-cc dev, just manually set host to something
30
// else and comment this out. That's the only way, since dev is otherwise
31
// impossible because otherwise the haproxy server sends queries
32
// all straight to the production share server!
33
const vhost: string | undefined = req.headers.host?.toLowerCase();
34
// const vhost = "vertramp.org";
35
// const vhost = "python-wasm.org";
36
if (vhost == null) {
37
// logger.debug("no host header set");
38
next();
39
return;
40
}
41
logger.debug("checking for vhost", vhost);
42
43
const info = await getVirtualHostInfo(vhost);
44
if (info == null) {
45
// logger.debug("no vhost info for ", vhost);
46
next();
47
return;
48
}
49
50
let path = req.url;
51
if (basePath && basePath != "/") {
52
// This is only going to happen in case of doing
53
// cc-in-cc development.
54
path = req.url.slice(basePath.length);
55
}
56
if (path == "") {
57
path = "/";
58
}
59
60
// logger.debug({ vhost, url: req.url, info, path });
61
62
const isAuth: boolean = isAuthenticated({
63
req,
64
res,
65
path,
66
auth: info.auth,
67
});
68
69
if (!isAuth) {
70
logger.debug(
71
"not authenticated -- denying vhost='%s', path='%s'",
72
vhost,
73
path,
74
);
75
res.status(403).end();
76
return;
77
}
78
79
if (info.cross_origin_isolation) {
80
// The following two headers make it possible to serve content that used
81
// SharedArrayBuffer from vhosts and raw shared content. This is very
82
// important as it is a prerequisite for modern use of WebAssembly.
83
// E.g., https://python-wasm.cocalc.com uses this.
84
res.setHeader("Cross-origin-Embedder-Policy", "require-corp");
85
res.setHeader("Cross-origin-Opener-Policy", "same-origin");
86
}
87
88
const dir = pathToFiles(info.project_id, info.path);
89
/* logger.debug(
90
"serving virtual host path -- vhost='%s',dir='%s'",
91
vhost,
92
dir
93
); */
94
req.url = path;
95
staticHandler(dir, req, res, () => {
96
res.status(404).end();
97
});
98
};
99
}
100
101