synthwave/src/library/user.rs
2024-07-28 16:12:06 +02:00

105 lines
2.4 KiB
Rust

use data_encoding::HEXUPPER;
use mongod::{
assert_reference_of,
derive::{Model, Referencable},
Model, Referencable, Reference, Validate,
};
use mongodb::bson::doc;
use rand::RngCore;
use serde::{Deserialize, Serialize};
use serde_json::json;
fn gen_token(token_length: usize) -> String {
let mut token_bytes = vec![0u8; token_length];
rand::thread_rng().fill_bytes(&mut token_bytes);
HEXUPPER.encode(&token_bytes)
}
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
pub struct User {
pub _id: String,
pub username: String,
pub password: String,
pub role: UserRole,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum UserRole {
Regular,
Admin,
}
impl Validate for User {
async fn validate(&self) -> Result<(), String> {
Ok(())
}
}
impl User {
pub async fn create(username: &str, password: &str, role: UserRole) -> Option<Self> {
if User::find_one_partial(doc! { "username": username }, json!({}))
.await
.is_some()
{
return None;
}
let u = User {
_id: uuid::Uuid::new_v4().to_string(),
username: username.to_string(),
password: bcrypt::hash(password, bcrypt::DEFAULT_COST).unwrap(),
role,
};
u.insert().await.ok()?;
Some(u)
}
pub async fn login(username: &str, password: &str) -> Option<Session> {
let u = User::find_one(doc! { "username": username }).await?;
if !u.verify_pw(password) {
return None;
}
Some(u.session().await)
}
pub async fn session(&self) -> Session {
let s = Session {
_id: uuid::Uuid::new_v4().to_string(),
token: gen_token(60),
user: self.reference(),
};
s.insert().await.unwrap();
s
}
pub fn is_admin(&self) -> bool {
matches!(self.role, UserRole::Admin)
}
pub fn verify_pw(&self, password: &str) -> bool {
bcrypt::verify(password, &self.password).unwrap()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
pub struct Session {
pub _id: String,
pub token: String,
pub user: Reference,
}
impl Validate for Session {
async fn validate(&self) -> Result<(), String> {
assert_reference_of!(self.user, User);
Ok(())
}
}