firecloud-cli 0.2.0

Command-line interface for FireCloud P2P messaging and file sharing
//! Password utilities for KEK encryption

use anyhow::{Context, Result};
use firecloud_crypto::{generate_salt, Kek, SALT_SIZE};
use std::io::{self, Write};

/// Prompt user for a password (with confirmation)
pub fn prompt_password_with_confirmation(prompt: &str) -> Result<String> {
    loop {
        let password = rpassword::prompt_password(prompt)
            .context("Failed to read password")?;
        
        if password.is_empty() {
            eprintln!("❌ Password cannot be empty. Please try again.");
            continue;
        }
        
        if password.len() < 8 {
            eprintln!("⚠️  Warning: Password is too short (< 8 characters). Recommended: 12+ characters.");
        }
        
        let confirm = rpassword::prompt_password("Confirm password: ")
            .context("Failed to read password confirmation")?;
        
        if password == confirm {
            return Ok(password);
        }
        
        eprintln!("❌ Passwords don't match. Please try again.\n");
    }
}

/// Prompt user for a password (single entry)
pub fn prompt_password(prompt: &str) -> Result<String> {
    rpassword::prompt_password(prompt)
        .context("Failed to read password")
}

/// Prompt user whether to use encryption
pub fn prompt_use_encryption() -> Result<bool> {
    print!("🔐 Encrypt this file with a password? [Y/n]: ");
    io::stdout().flush()?;
    
    let mut input = String::new();
    io::stdin().read_line(&mut input)?;
    
    let answer = input.trim().to_lowercase();
    Ok(answer.is_empty() || answer == "y" || answer == "yes")
}

/// Derive KEK from password and generate salt
pub fn derive_kek_with_new_salt(password: &str) -> Result<(Kek, [u8; SALT_SIZE])> {
    let salt = generate_salt();
    let kek = Kek::derive_from_password(password, &salt)
        .context("Failed to derive encryption key from password")?;
    Ok((kek, salt))
}

/// Derive KEK from password with existing salt
pub fn derive_kek(password: &str, salt: &[u8]) -> Result<Kek> {
    if salt.len() != SALT_SIZE {
        anyhow::bail!("Invalid salt size: expected {}, got {}", SALT_SIZE, salt.len());
    }
    
    let salt_array: [u8; SALT_SIZE] = salt.try_into()
        .context("Failed to convert salt to array")?;
    
    Kek::derive_from_password(password, &salt_array)
        .context("Failed to derive encryption key from password")
}