2024-02-10 12:06:53 +01:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2024-02-10 13:07:36 +01:00
|
|
|
use rand::{seq::IteratorRandom, thread_rng};
|
2024-02-10 13:08:45 +01:00
|
|
|
use thiserror::Error;
|
2024-02-10 12:06:53 +01:00
|
|
|
use tokio::sync::Mutex;
|
2024-02-10 13:07:36 +01:00
|
|
|
use tracing::{event, instrument, Level};
|
2024-02-10 11:10:58 +01:00
|
|
|
|
2024-02-10 12:32:01 +01:00
|
|
|
use crate::{
|
2024-02-10 13:07:36 +01:00
|
|
|
db::{/* Database, */ Database, SqliteDatabase},
|
2024-02-10 12:32:01 +01:00
|
|
|
secrets::{Password, UserToken},
|
|
|
|
};
|
2024-02-10 11:10:58 +01:00
|
|
|
|
2024-02-10 13:08:45 +01:00
|
|
|
#[derive(Debug, Error)]
|
|
|
|
pub enum AuthenticationError {
|
|
|
|
#[error("Invalid username or password")]
|
|
|
|
InvalidUserOrPassword,
|
|
|
|
#[error("Invalid token")]
|
|
|
|
InvalidToken,
|
|
|
|
#[error("Invalid server hash")]
|
|
|
|
InvalidServerHash,
|
|
|
|
#[error("Authentication backend error")]
|
|
|
|
Backend(#[from] sqlx::Error),
|
|
|
|
}
|
|
|
|
|
2024-02-10 11:20:35 +01:00
|
|
|
#[derive(Debug)]
|
2024-02-10 12:56:35 +01:00
|
|
|
pub struct Authenticator {
|
|
|
|
db: Arc<Mutex<SqliteDatabase>>,
|
2024-02-10 10:51:56 +01:00
|
|
|
}
|
|
|
|
|
2024-02-10 12:56:35 +01:00
|
|
|
impl Authenticator {
|
2024-02-10 12:06:53 +01:00
|
|
|
pub fn new(db: Arc<Mutex<SqliteDatabase>>) -> Self {
|
|
|
|
Self { db }
|
2024-02-10 10:51:56 +01:00
|
|
|
}
|
|
|
|
|
2024-02-10 11:20:35 +01:00
|
|
|
#[instrument]
|
2024-02-10 12:06:53 +01:00
|
|
|
pub async fn create_user_token(&mut self, username: &str, password: &Password) -> UserToken {
|
2024-02-10 13:07:36 +01:00
|
|
|
let mut token_str = "".to_owned();
|
|
|
|
|
|
|
|
let mut rng = thread_rng();
|
|
|
|
for _ in 0..30 {
|
|
|
|
let digit = (0..=15).choose(&mut rng).unwrap();
|
|
|
|
let char = (('a' as u8) + digit) as char;
|
|
|
|
token_str.push(char)
|
|
|
|
}
|
|
|
|
|
|
|
|
let new_token = UserToken::from(token_str);
|
|
|
|
|
|
|
|
let mut db = self.db.lock().await;
|
|
|
|
if let Err(err) = db.save_token(username, &new_token).await {
|
|
|
|
event!(Level::ERROR, %err, "Failed to save token in database");
|
|
|
|
}
|
|
|
|
|
|
|
|
new_token
|
2024-02-10 11:11:46 +01:00
|
|
|
}
|
|
|
|
|
2024-02-10 11:20:35 +01:00
|
|
|
#[instrument]
|
2024-02-10 13:08:45 +01:00
|
|
|
pub async fn verify_user_token(
|
|
|
|
&self,
|
|
|
|
username: &str,
|
|
|
|
token: &UserToken,
|
|
|
|
) -> Result<(), AuthenticationError> {
|
2024-02-10 13:10:54 +01:00
|
|
|
let mut db = self.db.lock().await;
|
|
|
|
|
|
|
|
// TODO: (in db) distinguish between invalid token and SQLX error
|
2024-02-10 13:08:45 +01:00
|
|
|
db.get_token(username).await?;
|
|
|
|
|
|
|
|
Ok(())
|
2024-02-10 10:51:56 +01:00
|
|
|
}
|
|
|
|
}
|