// Boot-time validation of BOT_INTERNAL_KEY — the shared secret that is the ONLY // auth on the server<->bot /internal/* routes (which return the decrypted Discord // bot token). A missing, placeholder, or trivially short key would leave that // endpoint effectively unguarded, so in production we refuse to start; in dev we // warn but continue so local work isn't blocked. See issue #33. // The placeholders shipped in the repo's .env.example files. If any of these // reaches production it means the operator never generated a real key. const PLACEHOLDERS = new Set([ 'change-me-to-a-long-random-string', // root .env.example 'dev-only-change-me-bot-key', // server/.env.example, bot/.env.example ]) const MIN_LENGTH = 16 // Returns { ok, fatal, message }. `fatal` is only ever true in production — // callers should exit non-zero on fatal, and log a warning (but continue) when // !ok && !fatal. function evaluateBotInternalKey({ key, nodeEnv } = {}) { const value = key || '' let reason = null if (value.length === 0) reason = 'BOT_INTERNAL_KEY is not set' else if (PLACEHOLDERS.has(value)) reason = 'BOT_INTERNAL_KEY is still the documented placeholder value' else if (value.length < MIN_LENGTH) reason = `BOT_INTERNAL_KEY is too short (< ${MIN_LENGTH} chars)` if (!reason) return { ok: true, fatal: false, message: null } const production = nodeEnv === 'production' const detail = `${reason}. It is the only guard on /internal/bot-config, which returns the ` + 'decrypted Discord bot token.' return { ok: false, fatal: production, message: production ? `${detail} Refusing to start in production — set a long random BOT_INTERNAL_KEY (matching bot/.env).` : `${detail} Continuing because NODE_ENV is not "production" — set a strong value before deploying.`, } } module.exports = { evaluateBotInternalKey, PLACEHOLDERS, MIN_LENGTH }