/**
 * Master-key bootstrap.
 *
 * Resolution order:
 *   1. STUDIOGRAPH_MASTER_KEY env var (base64-encoded 32 bytes).
 *      Always wins. In production this is the only acceptable source.
 *   2. ~/.studiograph/master-key file (mode 0600). Local-dev only.
 *      If absent, a fresh 32-byte key is generated, written, and a one-time
 *      warning printed to stderr with backup instructions.
 *
 * Production gate: when RAILWAY_ENVIRONMENT is set and the env-var is
 * unset, throw. We do NOT silently generate a key in production — that
 * would be ephemeral, would invalidate every encrypted row on the next
 * restart, and would mask a misconfigured deploy.
 */
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { generateMasterKey } from './encryption.js';
const MASTER_KEY_ENV = 'STUDIOGRAPH_MASTER_KEY';
const MASTER_KEY_PREVIOUS_ENV = 'STUDIOGRAPH_MASTER_KEY_PREVIOUS';
/**
 * Default location of the local-dev fallback file.
 */
function defaultMasterKeyPath() {
    return join(homedir(), '.studiograph', 'master-key');
}
function isProduction() {
    return Boolean(process.env.RAILWAY_ENVIRONMENT);
}
function decodeBase64Key(raw, source) {
    const trimmed = raw.trim();
    let bytes;
    try {
        bytes = new Uint8Array(Buffer.from(trimmed, 'base64'));
    }
    catch {
        throw new Error(`master-key: ${source} is not valid base64`);
    }
    if (bytes.length !== 32) {
        throw new Error(`master-key: ${source} decoded to ${bytes.length} bytes (need 32)`);
    }
    return bytes;
}
/**
 * Load the master key. Idempotent — safe to call multiple times.
 *
 * In a long-running process you should call once at boot and cache the
 * result. The local-dev side-effect (file generate + warn) only fires if
 * the file does not exist.
 */
export function loadMasterKey(opts = {}) {
    const envValue = process.env[MASTER_KEY_ENV];
    if (envValue && envValue.trim()) {
        return {
            key: decodeBase64Key(envValue, `${MASTER_KEY_ENV} env var`),
            source: 'env',
        };
    }
    // Production must be env-only. Fall through is misconfiguration.
    if (isProduction()) {
        throw new Error(`master-key: ${MASTER_KEY_ENV} is required in production (RAILWAY_ENVIRONMENT is set). ` +
            `Generate one with: node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"`);
    }
    // Local-dev: file fallback.
    const filePath = opts.filePath ?? defaultMasterKeyPath();
    if (existsSync(filePath)) {
        const raw = readFileSync(filePath, 'utf-8');
        return {
            key: decodeBase64Key(raw, `master-key file at ${filePath}`),
            source: 'file',
            filePath,
        };
    }
    // First-run on local dev: generate and persist.
    const key = generateMasterKey();
    const b64 = Buffer.from(key).toString('base64');
    // Make sure the parent directory exists with restrictive mode.
    mkdirSync(join(filePath, '..'), { recursive: true, mode: 0o700 });
    // mkdirSync's mode is masked by umask, so retighten.
    try {
        chmodSync(join(filePath, '..'), 0o700);
    }
    catch { /* non-fatal */ }
    writeFileSync(filePath, b64, { mode: 0o600 });
    try {
        chmodSync(filePath, 0o600);
    }
    catch { /* non-fatal */ }
    // One-time stderr warning. Local-dev UX only; production never lands here.
    // Stderr because stdout is reserved for app output and could be piped.
    process.stderr.write([
        '',
        '─'.repeat(72),
        'studiograph: generated a new master key (first run)',
        `  Location: ${filePath}`,
        '  Mode:     0600 (owner read/write only)',
        '',
        `  This key encrypts the secrets store. If you lose it, every encrypted`,
        `  row in secrets.db is permanently unrecoverable.`,
        '',
        `  Back it up. To export for a different environment:`,
        `    cat ${filePath}`,
        `  Then set in the new environment:`,
        `    ${MASTER_KEY_ENV}=<contents>`,
        '─'.repeat(72),
        '',
    ].join('\n'));
    return { key, source: 'generated', filePath };
}
/**
 * Optional companion: load a previous master key for rotation transitions.
 * Returns undefined when STUDIOGRAPH_MASTER_KEY_PREVIOUS is unset — that's
 * the steady state. Caller must tolerate undefined.
 */
export function loadPreviousMasterKey() {
    const v = process.env[MASTER_KEY_PREVIOUS_ENV];
    if (!v || !v.trim())
        return undefined;
    return decodeBase64Key(v, `${MASTER_KEY_PREVIOUS_ENV} env var`);
}
//# sourceMappingURL=master-key.js.map