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/get-vhost-info.ts
Views: 687
1
import getPool from "@cocalc/database/pool";
2
import { getLogger } from "@cocalc/backend/logger";
3
import LRU from "lru-cache";
4
5
const logger = getLogger("get-vhost-info");
6
7
export interface Auth {
8
name: string;
9
pass: string; // password-hash
10
}
11
12
export type VirtualHostInfo = { [path: string]: Auth[] };
13
14
interface HostInfo {
15
project_id: string;
16
path: string;
17
auth: VirtualHostInfo;
18
cross_origin_isolation?: boolean;
19
}
20
21
// This could get called a LOT on the same host that is not special
22
// for the server, and also the list of public projects that have
23
// vhost info is very small (e.g., like 10 of them) and at least
24
// right now only something that is manually changed! We thus cache
25
// the answer for 1 minute. If we change our use of vhosts, we can
26
// revisit this parameter.
27
28
const cache = new LRU<string, HostInfo | null>({
29
ttl: 1000 * 60,
30
max: 1000,
31
});
32
33
export default async function getVirtualHostInfo(
34
vhost: string
35
): Promise<HostInfo | null | undefined> {
36
if (cache.has(vhost)) {
37
//logger.debug("using cache");
38
return cache.get(vhost);
39
}
40
41
// long: once a vhost is set, it's unlikely to change for a while, since it literally
42
// requires updating DNS entries to have any impact.
43
const pool = getPool("long");
44
45
// Get the database entry that describes the public path with given vhost.
46
// NOTE: we are assuming there is at most one with a given vhost. If there
47
// are more, behavior is not defined, but that will get logged.
48
// As an optimization, we also check if vhost is null, to quickly remove the majority of entries (gives a 1000x speedup in prod).
49
const query = `SELECT project_id, path, auth, cross_origin_isolation
50
FROM public_paths
51
WHERE disabled IS NOT TRUE
52
AND vhost IS NOT NULL
53
AND $1::TEXT=ANY(string_to_array(vhost,','))`;
54
// logger.debug('query = ', query);
55
56
try {
57
const { rows } = await pool.query(query, [vhost]);
58
59
if (
60
rows.length == 0 ||
61
rows[0].project_id == null ||
62
rows[0].path == null
63
) {
64
// logger.debug("no valid virtual vhost=%s", vhost);
65
cache.set(vhost, null);
66
return null;
67
}
68
if (rows.length > 1) {
69
logger.warn("WARNING: multiple virtual host entries for vhost=%s", vhost);
70
}
71
const { project_id, path, auth, cross_origin_isolation } = rows[0]; // is a weird data type, which is why we don't just return it.
72
const r = { project_id, path, auth, cross_origin_isolation };
73
cache.set(vhost, r);
74
return r;
75
} catch (err) {
76
logger.error(`error querying for vhost ${vhost}`, err);
77
return null;
78
}
79
}
80
81