config.ts
Raw
1// Runtime configuration, read once from the environment at startup.
2// Defaults are chosen to be secure-but-non-breaking; tighten them in production
3// (see README for the full list and the "run behind TLS" note).
4
5const env = process.env;
6
7/** parseInt with a default that distinguishes "unset" from "explicit 0". All
8 * settings here are non-negative quantities, so a negative value falls back to
9 * the default rather than being passed through (e.g. busboy fileSize: -5). */
10function intEnv(value: string | undefined, defaultValue: number): number {
11 if (value === undefined || value === "") return defaultValue;
12 const parsed = parseInt(value, 10);
13 return Number.isFinite(parsed) && parsed >= 0 ? parsed : defaultValue;
14}
15
16/** Truthy only for "true"/"1"; anything else (incl. "false", "0", unset) is off. */
17function boolEnv(value: string | undefined): boolean {
18 return value === "true" || value === "1";
19}
20
21export const config = {
22 // Hard cap on a single upload, in bytes (default 100 MiB).
23 maxUploadBytes: intEnv(Bun.env.MAX_UPLOAD_BYTES, 100 * 1024 * 1024),
24 // Maximum retention in minutes. null = unlimited; when set, every upload's
25 // deletion time is clamped to at most now + maxAgeMinutes.
26 maxAgeMinutes: Bun.env.MAX_AGE_MINUTES
27 ? intEnv(Bun.env.MAX_AGE_MINUTES, 0) || null
28 : null,
29 // Minimum seconds between uploads from the same client IP. 0 = disabled.
30 uploadCooldownSeconds: intEnv(Bun.env.UPLOAD_COOLDOWN_SECONDS, 0),
31 // Minimum seconds between server-side decryption attempts from the same client
32 // IP. 0 = disabled. Bounds the PBKDF2 CPU cost an attacker who knows a UUID can
33 // force by hammering /show or /raw with password cookies.
34 decryptCooldownSeconds: intEnv(Bun.env.DECRYPT_COOLDOWN_SECONDS, 0),
35 // Cap on total stored content bytes across all files. null = unlimited; when
36 // set, an upload that would push the total over the cap is rejected (507).
37 maxTotalBytes: Bun.env.MAX_TOTAL_BYTES
38 ? intEnv(Bun.env.MAX_TOTAL_BYTES, 0) || null
39 : null,
40 // Set when running behind a trusted TLS-terminating reverse proxy (the usual
41 // production setup). Enables reading X-Forwarded-For / X-Real-IP for the
42 // client IP and adds the Secure flag to the password cookie. Leave off for
43 // direct/local HTTP, otherwise clients can spoof the cooldown key and the
44 // Secure cookie won't be sent over plain HTTP.
45 behindProxy: boolEnv(env.BEHIND_PROXY),
46};
47