password_strength/lib.rs
1pub mod analyzer;
2
3use crate::analyzer::Analyzer;
4use crate::analyzer::charset::CharsetAnalyzer;
5use crate::analyzer::length::LengthAnalyzer;
6use crate::analyzer::pattern::PatternAnalyzer;
7use crate::analyzer::trigraph::TrigraphAnalyzer;
8
9/// Estimates the overall password strength by combining scores from multiple analyzers
10/// using a direct weighted average.
11///
12/// This function calculates a weighted score based on length, character set diversity,
13/// trigraph randomness, and the pattern score (which reflects the absence of weak patterns).
14///
15/// # Arguments
16///
17/// * `password` - The password string slice to analyze.
18///
19/// # Returns
20///
21/// A score between 0.0 (very weak) and 1.0 (very strong) as an f32.
22///
23/// # Example Usage
24///
25/// ```
26/// use password_strength::estimate_strength;
27/// let password_weak = "password";
28/// let password_strong = "aB1!üöß字例😊_Long"; // Example of a potentially strong password
29///
30/// let strength_weak = estimate_strength(password_weak);
31/// let strength_strong = estimate_strength(password_strong);
32///
33/// println!("Strength of '{}': {:.3}", password_weak, strength_weak);
34/// println!("Strength of '{}': {:.3}", password_strong, strength_strong);
35/// ```
36pub fn estimate_strength(password: &str) -> f32 {
37 if password.is_empty() {
38 return 0.0;
39 }
40
41 let length_analyzer = LengthAnalyzer;
42 let charset_analyzer = CharsetAnalyzer;
43 let trigraph_analyzer = TrigraphAnalyzer;
44 let pattern_analyzer = PatternAnalyzer::default();
45
46 // Each score is between 0.0 and 1.0
47 let score_length = length_analyzer.analyze(password);
48 let score_charset = charset_analyzer.analyze(password);
49 let score_trigraph = trigraph_analyzer.analyze(password);
50 let score_pattern = pattern_analyzer.analyze(password);
51
52 // These weights determine the contribution of each aspect to the final score.
53 // They must sum to 1.0.
54 const WEIGHT_LENGTH: f32 = 0.25;
55 const WEIGHT_CHARSET: f32 = 0.25;
56 const WEIGHT_TRIGRAPH: f32 = 0.10;
57 const WEIGHT_PATTERN: f32 = 0.40;
58
59 // Direct weighted average of all four scores.
60 let final_score = (WEIGHT_LENGTH * score_length)
61 + (WEIGHT_CHARSET * score_charset)
62 + (WEIGHT_TRIGRAPH * score_trigraph)
63 + (WEIGHT_PATTERN * score_pattern);
64
65 // Since all scores are [0, 1] and weights sum to 1.0, the result
66 // should theoretically be [0, 1]. Clamping provides robustness.
67 final_score.clamp(0.0, 1.0)
68}