import { encryptField, decryptField } from './encrypted-fields.js';
/**
 * High-level helpers for storing per-user secrets (TOTP secret, OAuth tokens,
 * webhook signing keys) at rest. Wraps the raw `encryptField`/`decryptField`
 * primitives so callers don't have to plumb `CMS_ENCRYPTION_KEY` through every
 * code path.
 *
 * Encrypted values are tagged with a version prefix so we can rotate keys or
 * change the encoding without breaking existing rows. Plaintext values written
 * before encryption was enabled are passed through unchanged on read so
 * upgrades don't break existing data — call `migrateSecret()` when you want
 * to opportunistically re-encrypt them on next access.
 */
const PREFIX = 'enc:v1:';
function getKey() {
    const key = process.env.CMS_ENCRYPTION_KEY;
    if (!key)
        return null;
    // 32 bytes = 64 hex chars
    if (key.length !== 64) {
        console.warn('[actuate][crypto] CMS_ENCRYPTION_KEY must be 64 hex characters (32 bytes); got ' +
            key.length +
            '. Falling back to plaintext storage. Generate with: ' +
            "node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"");
        return null;
    }
    return key;
}
/**
 * Encrypt a value for storage. Returns the original value unchanged when no
 * encryption key is configured (development convenience). Production deployments
 * MUST set `CMS_ENCRYPTION_KEY` — see `security.mdc`.
 */
export async function encryptSecret(plaintext) {
    if (!plaintext)
        return plaintext;
    const key = getKey();
    if (!key)
        return plaintext;
    const ciphertext = await encryptField(plaintext, key);
    return PREFIX + ciphertext;
}
/**
 * Decrypt a value that was stored via `encryptSecret`. Plaintext values
 * (written before encryption was enabled, or written by a deployment without
 * the key) are returned unchanged.
 */
export async function decryptSecret(stored) {
    if (!stored)
        return stored;
    if (!stored.startsWith(PREFIX))
        return stored;
    const key = getKey();
    if (!key) {
        throw new Error('CMS_ENCRYPTION_KEY is required to decrypt this value but is not set. ' +
            'Configure the same key used at write time.');
    }
    return decryptField(stored.slice(PREFIX.length), key);
}
/** True when the value is stored encrypted (and therefore needs decryption). */
export function isEncrypted(value) {
    return typeof value === 'string' && value.startsWith(PREFIX);
}
/**
 * Encrypt each string element in an array. Returns the array unchanged when
 * encryption is disabled. Used for things like TOTP backup codes.
 */
export async function encryptStringArray(values) {
    return Promise.all(values.map((v) => encryptSecret(v)));
}
/** Decrypt each element in an array stored via `encryptStringArray`. */
export async function decryptStringArray(values) {
    return Promise.all(values.map((v) => decryptSecret(v)));
}
//# sourceMappingURL=secret-storage.js.map