modcli/output/input/
password.rs

1use crate::output::print;
2use rpassword::read_password;
3
4/// Prompts the user for a password (no echo).
5///
6/// Behavior:
7/// - On I/O failure, logs an error via `output::print` and retries when using
8///   `prompt_password_with_validation`. The simple `prompt_password` variant
9///   returns an empty string on error.
10pub fn prompt_password(message: &str) -> String {
11    prompt_password_with_validation(message, |_| Ok(()))
12}
13
14/// Prompts for a password with validation.
15///
16/// Behavior:
17/// - On I/O failure, logs an error via `output::print` and retries.
18/// - On validation failure, shows a status message and retries.
19pub fn prompt_password_with_validation<F>(message: &str, validator: F) -> String
20where
21    F: Fn(&str) -> Result<(), &str>,
22{
23    loop {
24        print!("{message}: ");
25        if let Err(e) = std::io::Write::flush(&mut std::io::stdout()) {
26            print::warn(&format!("flush failed: {e}"));
27        }
28        let password = match read_password() {
29            Ok(p) => p,
30            Err(e) => {
31                print::error(&format!("Failed to read password: {e}. Try again."));
32                continue;
33            }
34        };
35
36        match validator(password.trim()) {
37            Ok(_) => return password.trim().to_string(),
38            Err(err) => print::status(&format!("Invalid password: {err}")),
39        }
40    }
41}