seednaut 0.1.1

A command-line utility for inspecting, verifying, and extracting Seedvault Android backups
use anyhow::Result;
use indicatif::ProgressBar;
use std::path::PathBuf;
use std::time::Duration;

use crate::engine::crypto::{DerivedKeys, derive_keys};
use crate::engine::scanner::discover_snapshots;
use crate::engine::types::SnapshotInfo;
use crate::ui::mnemonic::get_mnemonic;

pub struct AppContext {
    pub input_path: PathBuf,
    pub derived_keys: DerivedKeys,
    pub snapshots: Vec<SnapshotInfo>,
}

pub fn init_context(input_path: PathBuf) -> Result<AppContext> {
    if !input_path.exists() {
        anyhow::bail!(
            "The specified input path does not exist: {}",
            input_path.display()
        );
    }

    let mnemonic = get_mnemonic()?;
    let derived_keys = derive_keys(&mnemonic)?;

    let spinner_style = crate::ui::style::spinner();
    let spinner = ProgressBar::new_spinner().with_style(spinner_style);
    spinner.enable_steady_tick(Duration::from_millis(80));
    spinner.set_message("Discovering and decrypting snapshots...");

    let discovery = discover_snapshots(&input_path, &derived_keys)?;
    let (snapshots, failed) = (discovery.snapshots, discovery.failed);

    let msg = if snapshots.is_empty() && failed.is_empty() {
        "No backup data found at this location.".to_string()
    } else if snapshots.is_empty() {
        "No snapshots could be decrypted. The mnemonic may be incorrect.".to_string()
    } else if !failed.is_empty() {
        format!(
            "{} of {} snapshots could not be decrypted:",
            failed.len(),
            snapshots.len() + failed.len()
        )
    } else {
        format!("Discovered {} snapshot(s).", snapshots.len())
    };
    spinner.finish_with_message(msg);

    if !snapshots.is_empty() && !failed.is_empty() {
        for f in &failed {
            eprintln!("  - {}", f);
        }
    }

    Ok(AppContext {
        input_path,
        derived_keys,
        snapshots,
    })
}