feat: DB operations can fail

This commit is contained in:
selfhoster selfhoster 2026-09-01 23:27:02 +02:00
commit 7527ba7a09
6 changed files with 50 additions and 19 deletions

View file

@ -2,6 +2,7 @@ use tokio::sync::RwLock;
use std::sync::Arc;
use crate::db::error::BoxedError;
use crate::db::{DatabaseInterface, UserRef};
#[derive(Clone, Debug)]
@ -26,13 +27,13 @@ impl<D: DatabaseInterface> Database<D> {
/// TODO: we may want to make sure the method runs in constant time
/// to avoid leaking information about existing users...
/// or maybe we do not care.
pub async fn check_password(&self, user: &UserRef, password: &str) -> bool {
let Some(user) = self.get_user(user).await else {
pub async fn check_password(&self, user: &UserRef, password: &str) -> Result<bool, BoxedError> {
let Some(user) = self.get_user(user).await? else {
tracing::debug!("check_password: User not found {user}");
return false;
return Ok(false);
};
tracing::debug!("Comparing {} and {}", user.password, password);
user.password == password
Ok(user.password == password)
}
}

View file

@ -2,6 +2,8 @@ use std::fmt;
use crate::db::UserRef;
pub type BoxedError = Box<dyn std::error::Error + Send + Sync + 'static>;
#[derive(Debug)]
pub struct UserAlreadyExists(pub UserRef);

View file

@ -1,17 +1,23 @@
use crate::db::error::UserAlreadyExists;
use crate::db::error::{BoxedError, UserAlreadyExists};
use crate::db::{Database, User, UserRef};
impl<D: DatabaseInterface> DatabaseInterface for Database<D> {
async fn get_user(&self, user: &UserRef) -> Option<User> {
async fn get_user(&self, user: &UserRef) -> Result<Option<User>, BoxedError> {
self.inner.read().await.get_user(user).await
}
async fn create_user(&mut self, user: User) -> Result<(), UserAlreadyExists> {
async fn create_user(
&mut self,
user: User,
) -> Result<Result<(), UserAlreadyExists>, BoxedError> {
self.inner.write().await.create_user(user).await
}
}
pub trait DatabaseInterface {
async fn get_user(&self, user: &UserRef) -> Option<User>;
async fn create_user(&mut self, user: User) -> Result<(), UserAlreadyExists>;
async fn get_user(&self, user: &UserRef) -> Result<Option<User>, BoxedError>;
async fn create_user(
&mut self,
user: User,
) -> Result<Result<(), UserAlreadyExists>, BoxedError>;
}

View file

@ -1,6 +1,6 @@
use std::future::{Future, ready};
use crate::db::error::UserAlreadyExists;
use crate::db::error::{BoxedError, UserAlreadyExists};
use crate::db::{Database, DatabaseInterface, Group, User, UserRef};
#[derive(Clone, Debug, Default)]
@ -16,23 +16,29 @@ impl MemoryDatabase {
}
impl DatabaseInterface for MemoryDatabase {
fn get_user(&self, req_user: &UserRef) -> impl Future<Output = Option<User>> {
fn get_user(
&self,
req_user: &UserRef,
) -> impl Future<Output = Result<Option<User>, BoxedError>> {
for user in &self.users {
if user.username == req_user.username && user.domain == req_user.domain {
return ready(Some(user.clone()));
return ready(Ok(Some(user.clone())));
}
}
ready(None)
ready(Ok(None))
}
async fn create_user(&mut self, user: User) -> Result<(), UserAlreadyExists> {
async fn create_user(
&mut self,
user: User,
) -> Result<Result<(), UserAlreadyExists>, BoxedError> {
let user_ref = user.user_ref();
if self.get_user(&user_ref).await.is_some() {
return Err(UserAlreadyExists(user_ref));
if self.get_user(&user_ref).await?.is_some() {
return Ok(Err(UserAlreadyExists(user_ref)));
}
self.users.push(user);
Ok(())
Ok(Ok(()))
}
}