sarhash-core 0.1.0

A modular library for password hashing (Argon2) and strength verification (zxcvbn).
Documentation
use serde::{Deserialize, Serialize};
use zxcvbn::zxcvbn;

#[derive(Debug, Serialize, Deserialize)]
pub struct StrengthResult {
    /// Integer from 0-4 (0 being weakest, 4 being strongest)
    pub score: u8,
    /// Estimated offline crack time in seconds
    pub crack_time_seconds: f64,
    /// Feedback/Suggestions (optional simple warning if available)
    pub warning: Option<String>,
    /// List of suggestions
    pub suggestions: Vec<String>,
}

/// Checks the strength of a password using zxcvbn.
pub fn check_strength(password: &str) -> StrengthResult {
    let result = zxcvbn(password, &[]);

    // Using simple approach first to get it to compile
    // Note: zxcvbn 3.0+ API might differ from what I recalled.

    let feedback = result.feedback();

    let warning = if let Some(feedback) = feedback {
        if feedback.warning().is_some() {
            feedback.warning().map(|w| w.to_string())
        } else {
            None
        }
    } else {
        None
    };

    let suggestions = if let Some(feedback) = feedback {
        feedback
            .suggestions()
            .iter()
            .map(|s| s.to_string())
            .collect()
    } else {
        Vec::new()
    };

    // Crack times seems to cause issues, let's inspect what's available or use a default
    // We'll fix this in the next step
    // let guesses = result.crack_times().guesses; // Field is private
    let crack_time_seconds = 0.0; // Unavailable in this version of zxcvbn crate without usage of private fields

    StrengthResult {
        score: result.score().try_into().unwrap_or(0),
        crack_time_seconds,
        warning,
        suggestions,
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_weak_password() {
        let result = check_strength("password");
        assert_eq!(result.score, 0);
    }

    #[test]
    fn test_strong_password() {
        // "correct horse battery staple" is the classic example of high entropy but memorable
        let result = check_strength("correct horse battery staple");
        assert!(result.score >= 3);
    }
}