// Vault: password-based encryption of secrets using libsodium.
// Uses Argon2id for key derivation and XSalsa20-Poly1305 for encryption.
// All crypto operations are delegated to libsodium — no raw primitives.

const sodium = require("libsodium-wrappers-sumo");

let ready = false;

async function ensureReady() {
    if (!ready) {
        await sodium.ready;
        ready = true;
    }
}

// Returns { salt, nonce, ciphertext } (all base64-encoded strings).
async function encryptWithPassword(plaintext, password) {
    await ensureReady();
    const salt = sodium.randombytes_buf(sodium.crypto_pwhash_SALTBYTES);
    const key = sodium.crypto_pwhash(
        sodium.crypto_secretbox_KEYBYTES,
        password,
        salt,
        sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
        sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
        sodium.crypto_pwhash_ALG_ARGON2ID13,
    );
    const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
    const ciphertext = sodium.crypto_secretbox_easy(
        sodium.from_string(plaintext),
        nonce,
        key,
    );
    return {
        salt: sodium.to_base64(salt),
        nonce: sodium.to_base64(nonce),
        ciphertext: sodium.to_base64(ciphertext),
    };
}

// Returns the plaintext string, or throws on wrong password.
async function decryptWithPassword(encrypted, password) {
    await ensureReady();
    const salt = sodium.from_base64(encrypted.salt);
    const nonce = sodium.from_base64(encrypted.nonce);
    const ciphertext = sodium.from_base64(encrypted.ciphertext);
    const key = sodium.crypto_pwhash(
        sodium.crypto_secretbox_KEYBYTES,
        password,
        salt,
        sodium.crypto_pwhash_OPSLIMIT_INTERACTIVE,
        sodium.crypto_pwhash_MEMLIMIT_INTERACTIVE,
        sodium.crypto_pwhash_ALG_ARGON2ID13,
    );
    const plaintext = sodium.crypto_secretbox_open_easy(ciphertext, nonce, key);
    if (!plaintext) {
        throw new Error("Decryption failed — wrong password.");
    }
    return sodium.to_string(plaintext);
}

module.exports = { encryptWithPassword, decryptWithPassword };
