otter/src/db/repository/auth.rs

125 lines
3.7 KiB
Rust

use diesel::prelude::*;
use rand::Rng;
use super::SqliteRepository;
use crate::{
db::{self, schema::*},
gpodder::{self, AuthErr},
};
impl From<diesel::r2d2::PoolError> for gpodder::AuthErr {
fn from(value: diesel::r2d2::PoolError) -> Self {
Self::Other(Box::new(value))
}
}
impl From<diesel::result::Error> for gpodder::AuthErr {
fn from(value: diesel::result::Error) -> Self {
Self::Other(Box::new(value))
}
}
impl gpodder::AuthRepository for SqliteRepository {
fn validate_credentials(
&self,
username: &str,
password: &str,
) -> Result<gpodder::models::User, AuthErr> {
if let Some(user) = users::table
.select(db::User::as_select())
.filter(users::username.eq(username))
.first(&mut self.pool.get()?)
.optional()?
{
if user.verify_password(password) {
Ok(gpodder::User {
id: user.id,
username: user.username,
})
} else {
Err(gpodder::AuthErr::InvalidPassword)
}
} else {
Err(gpodder::AuthErr::UnknownUser)
}
}
fn validate_session(&self, session_id: i64) -> Result<gpodder::User, gpodder::AuthErr> {
match sessions::dsl::sessions
.inner_join(users::table)
.filter(sessions::id.eq(session_id))
.select(db::User::as_select())
.get_result(&mut self.pool.get()?)
{
Ok(user) => Ok(gpodder::User {
id: user.id,
username: user.username,
}),
Err(diesel::result::Error::NotFound) => Err(gpodder::AuthErr::UnknownSession),
Err(err) => Err(gpodder::AuthErr::Other(Box::new(err))),
}
}
fn create_session(
&self,
username: &str,
password: &str,
) -> Result<(i64, gpodder::models::User), gpodder::AuthErr> {
if let Some(user) = users::table
.select(db::User::as_select())
.filter(users::username.eq(username))
.first(&mut self.pool.get()?)
.optional()?
{
if user.verify_password(password) {
let id: i64 = rand::thread_rng().gen();
let session_id = db::Session {
id,
user_id: user.id,
last_seen: chrono::Utc::now().timestamp(),
}
.insert_into(sessions::table)
.returning(sessions::id)
.get_result(&mut self.pool.get()?)?;
Ok((
session_id,
gpodder::User {
id: user.id,
username: user.username,
},
))
} else {
Err(gpodder::AuthErr::InvalidPassword)
}
} else {
Err(gpodder::AuthErr::UnknownUser)
}
}
fn remove_session(&self, username: &str, session_id: i64) -> Result<(), gpodder::AuthErr> {
let conn = &mut self.pool.get()?;
if let Some(user) = sessions::table
.inner_join(users::table)
.filter(sessions::id.eq(session_id))
.select(db::User::as_select())
.get_result(conn)
.optional()?
{
if user.username == username {
Ok(
diesel::delete(sessions::table.filter(sessions::id.eq(session_id)))
.execute(conn)
.map(|_| ())?,
)
} else {
Err(AuthErr::UnknownUser)
}
} else {
Ok(())
}
}
}