aboutsummaryrefslogtreecommitdiff
path: root/src/auth/pin.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/auth/pin.rs')
-rw-r--r--src/auth/pin.rs66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/auth/pin.rs b/src/auth/pin.rs
new file mode 100644
index 0000000..4d1993c
--- /dev/null
+++ b/src/auth/pin.rs
@@ -0,0 +1,66 @@
+// PIN authentication module
+use crate::config::SecurityConfig;
+use crate::models::{Role, User};
+use anyhow::{Context, Result};
+use sqlx::MySqlPool;
+
+pub async fn authenticate_pin(
+ pool: &MySqlPool,
+ username: &str,
+ pin: &str,
+ security_config: &SecurityConfig,
+) -> Result<Option<(User, Role)>> {
+ // Fetch user from database
+ let user: Option<User> = sqlx::query_as::<_, User>(
+ r#"
+ SELECT id, name, username, password, pin_code, login_string, role_id,
+ email, phone, notes, active, last_login_date, created_date,
+ password_reset_token, password_reset_expiry
+ FROM users
+ WHERE username = ? AND active = TRUE AND pin_code IS NOT NULL
+ "#,
+ )
+ .bind(username)
+ .fetch_optional(pool)
+ .await
+ .context("Failed to fetch user from database")?;
+
+ if let Some(user) = user {
+ // Check if user has a PIN set
+ if let Some(user_pin) = &user.pin_code {
+ // Verify PIN - either bcrypt hash or plaintext depending on config
+ let pin_valid = if security_config.hash_pins {
+ bcrypt::verify(pin, user_pin).unwrap_or(false)
+ } else {
+ user_pin == pin
+ };
+
+ if pin_valid {
+ // Fetch user's role
+ let role: Role = sqlx::query_as::<_, Role>(
+ "SELECT id, name, power, created_at FROM roles WHERE id = ?",
+ )
+ .bind(user.role_id)
+ .fetch_one(pool)
+ .await
+ .context("Failed to fetch user role")?;
+
+ // Update last login date
+ sqlx::query("UPDATE users SET last_login_date = NOW() WHERE id = ?")
+ .bind(user.id)
+ .execute(pool)
+ .await
+ .context("Failed to update last login date")?;
+
+ Ok(Some((user, role)))
+ } else {
+ Ok(None)
+ }
+ } else {
+ // User doesn't have a PIN set
+ Ok(None)
+ }
+ } else {
+ Ok(None)
+ }
+}