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