105 lines
2.4 KiB
Rust
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(())
|
|
}
|
|
}
|