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(())
}
}
}