bucketwarden-auth 0.1.0

BucketWarden local identity, access key, and session credential store.
Documentation
use super::*;

impl AuthStore {
    pub fn record_login_success(&mut self, principal_id: &str, now_epoch_seconds: u64) {
        let record = self
            .login_attempts
            .entry(principal_id.to_string())
            .or_insert_with(|| LoginAttemptRecord {
                principal_id: principal_id.to_string(),
                ..LoginAttemptRecord::default()
            });
        record.consecutive_failed_attempts = 0;
        record.last_success_epoch_seconds = Some(now_epoch_seconds);
        record.last_failure_detail = None;
    }

    pub fn record_login_failure(
        &mut self,
        principal_id: &str,
        now_epoch_seconds: u64,
        detail: impl Into<String>,
    ) {
        let record = self
            .login_attempts
            .entry(principal_id.to_string())
            .or_insert_with(|| LoginAttemptRecord {
                principal_id: principal_id.to_string(),
                ..LoginAttemptRecord::default()
            });
        record.consecutive_failed_attempts = record.consecutive_failed_attempts.saturating_add(1);
        record.last_failed_epoch_seconds = Some(now_epoch_seconds);
        record.last_failure_detail = Some(detail.into());
    }

    pub fn login_attempt_record(&self, principal_id: &str) -> Option<&LoginAttemptRecord> {
        self.login_attempts.get(principal_id)
    }

    pub fn enforce_login_attempt_limit(
        &self,
        principal_id: &str,
        max_consecutive_failures: u32,
    ) -> Result<(), AuthError> {
        let blocked = self
            .login_attempt_record(principal_id)
            .is_some_and(|record| record.consecutive_failed_attempts >= max_consecutive_failures);
        if blocked {
            Err(AuthError::TooManyLoginAttempts(principal_id.to_string()))
        } else {
            Ok(())
        }
    }
}