cli: add 'rate <passphrase>' subcommand (zxcvbn)

This commit is contained in:
adlee-was-taken
2026-05-01 19:53:29 -04:00
parent 7bd1a9dd7d
commit ed2d299a92
2 changed files with 69 additions and 0 deletions

View File

@@ -179,6 +179,16 @@ enum Commands {
#[arg(value_enum)]
shell: Shell,
},
/// Rate a passphrase with zxcvbn — prints score (0-4) and estimated
/// guesses. Informational only; does not gate vault operations.
///
/// Pass `-` as the argument to read one line from stdin instead, which
/// keeps the passphrase out of shell history.
Rate {
/// Passphrase to score, or `-` to read from stdin.
passphrase: String,
},
}
#[derive(Subcommand)]
@@ -375,6 +385,7 @@ fn main() -> Result<()> {
generate(shell, &mut cmd, "relicario", &mut std::io::stdout());
Ok(())
}
Commands::Rate { passphrase } => cmd_rate(passphrase),
}
}
@@ -2180,3 +2191,28 @@ struct ParamsKdf {
argon2_t: u32,
argon2_p: u32,
}
fn cmd_rate(passphrase: String) -> Result<()> {
let pw: String = if passphrase == "-" {
use std::io::BufRead;
let stdin = std::io::stdin();
let mut line = String::new();
stdin.lock().read_line(&mut line)?;
line.trim_end_matches(&['\r', '\n'][..]).to_string()
} else {
passphrase
};
let est = relicario_core::generators::rate_passphrase(&pw);
let label = match est.score {
0 => "very weak",
1 => "weak",
2 => "fair",
3 => "good",
4 => "strong",
_ => "?",
};
println!("score: {}/4 ({})", est.score, label);
println!("guesses: ~10^{:.1}", est.guesses_log10);
println!("note: init requires score ≥ 3 (see `relicario init`)");
Ok(())
}