//! `relicario generate` — emit a fresh password or BIP39 passphrase. use anyhow::Result; pub fn cmd_generate( length: Option, bip39: bool, words: Option, symbols: Option, separator: Option, ) -> Result<()> { use relicario_core::{ generate_passphrase, generate_password, Capitalization, CharClasses, GeneratorRequest, SymbolCharset, }; // If we're inside a vault, unlock and pull `generator_defaults`. Outside // a vault, this stays a fast standalone CSPRNG tool (no unlock prompt). let vault_defaults: Option = if crate::helpers::vault_dir().is_ok() { let vault = crate::session::UnlockedVault::unlock_interactive()?; Some(vault.load_settings()?.generator_defaults) } else { None }; // `--bip39` flag forces Bip39 mode; otherwise use whatever mode the // vault default is in (Random when no vault). let use_bip39 = bip39 || matches!(vault_defaults, Some(GeneratorRequest::Bip39 { .. })); let output = if use_bip39 { let (def_words, def_sep, def_cap) = match &vault_defaults { Some(GeneratorRequest::Bip39 { word_count, separator, capitalization }) => { (*word_count, separator.clone(), *capitalization) } _ => (5, " ".to_string(), Capitalization::Lower), }; generate_passphrase(&GeneratorRequest::Bip39 { word_count: words.unwrap_or(def_words), separator: separator.unwrap_or(def_sep), capitalization: def_cap, })? } else { let (def_length, def_classes, def_charset) = match &vault_defaults { Some(GeneratorRequest::Random { length, classes, symbol_charset }) => { (*length, *classes, symbol_charset.clone()) } _ => ( 20, CharClasses { lower: true, upper: true, digits: true, symbols: true }, SymbolCharset::SafeOnly, ), }; let symbol_charset = match symbols.as_deref() { None => def_charset, Some("safe") => SymbolCharset::SafeOnly, Some("extended") => SymbolCharset::Extended, Some(other) => SymbolCharset::Custom(other.to_string()), }; generate_password(&GeneratorRequest::Random { length: length.unwrap_or(def_length), classes: def_classes, symbol_charset, })? }; println!("{}", output.as_str()); Ok(()) }