tenebrous-sheets/src/models/users.rs

62 lines
1.7 KiB
Rust

use crate::db::{Dao, TenebrousDbConn};
use crate::schema::users;
use argon2::{self, Config, Error as ArgonError};
use rand::Rng;
use rocket::outcome::IntoOutcome;
use rocket::request::{self, FromRequest, Request};
use serde_derive::Serialize;
pub(crate) fn hash_password(raw_password: &str) -> Result<String, ArgonError> {
let salt = rand::thread_rng().gen::<[u8; 16]>();
let config = Config::default();
argon2::hash_encoded(raw_password.as_bytes(), &salt, &config)
}
#[derive(Eq, PartialEq, Serialize, Debug, Queryable)]
pub struct User {
pub id: i32,
pub username: String,
pub password: String,
}
impl User {
pub fn verify_password(&self, raw_password: &str) -> bool {
argon2::verify_encoded(&self.password, raw_password.as_bytes()).unwrap_or(false)
}
}
async fn attempt_load_user<'a>(db: &'a TenebrousDbConn, id: i32) -> Option<User> {
db.load_user_by_id(id).await.ok().flatten()
}
#[rocket::async_trait]
impl<'a, 'r> FromRequest<'a, 'r> for &'a User {
type Error = ();
async fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, ()> {
let db = try_outcome!(request.guard::<TenebrousDbConn>().await);
let user_id: Option<i32> = request
.cookies()
.get_private("user_id")
.and_then(|cookie| cookie.value().parse().ok());
let user: &Option<User> = request
.local_cache_async(async {
match user_id {
Some(id) => attempt_load_user(&db, id).await,
_ => None,
}
})
.await;
user.as_ref().or_forward(())
}
}
#[derive(Insertable)]
#[table_name = "users"]
pub struct NewUser {
pub username: String,
pub password: String,
}