feat(backend): implemented basic permissions
This commit is contained in:
parent
c13c70e6e4
commit
d9480a8727
|
@ -8,4 +8,5 @@ pub struct ActivationTokensRow {
|
|||
pub struct UsersRow {
|
||||
pub userid: String,
|
||||
pub password: String,
|
||||
pub permissions: u16,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
mod db_structures;
|
||||
pub mod error;
|
||||
mod permissions;
|
||||
mod user;
|
||||
|
||||
use crate::backend::error::AccountRegisterError;
|
||||
use crate::config::Config;
|
||||
|
@ -11,6 +13,7 @@ use argon2::{
|
|||
use db_structures::{ActivationTokensRow, UsersRow};
|
||||
use log::info;
|
||||
use sqlx::{types::chrono::Utc, MySqlPool};
|
||||
use user::User;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -24,8 +27,9 @@ impl Backend {
|
|||
|
||||
sqlx::query!(
|
||||
r#"CREATE TABLE IF NOT EXISTS Users (
|
||||
userid UUID NOT NULL PRIMARY KEY,
|
||||
password VARCHAR(128) NOT NULL
|
||||
userid UUID NOT NULL PRIMARY KEY,
|
||||
password VARCHAR(128) NOT NULL,
|
||||
permissions SMALLINT UNSIGNED NOT NULL
|
||||
);"#
|
||||
)
|
||||
.execute(&pool)
|
||||
|
@ -90,7 +94,7 @@ impl Backend {
|
|||
}
|
||||
}
|
||||
|
||||
async fn get_user(&self, userid: Uuid) -> Result<Option<()>, sqlx::Error> {
|
||||
async fn get_user(&self, userid: Uuid) -> Result<Option<User>> {
|
||||
match sqlx::query_as!(
|
||||
UsersRow,
|
||||
r#"SELECT * FROM Users WHERE userid = ?;"#,
|
||||
|
@ -101,9 +105,9 @@ impl Backend {
|
|||
{
|
||||
Err(e) => match e {
|
||||
sqlx::Error::RowNotFound => Ok(None),
|
||||
_ => Err(e),
|
||||
_ => Err(e.into()),
|
||||
},
|
||||
Ok(_row) => Ok(Some(())),
|
||||
Ok(row) => Ok(Some(row.try_into()?)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +130,36 @@ impl Backend {
|
|||
let userid = Uuid::new_v4();
|
||||
|
||||
sqlx::query!(
|
||||
r#"INSERT INTO Users VALUES (?, ?);"#,
|
||||
r#"INSERT INTO Users VALUES (?, ?, 0);"#,
|
||||
userid.as_bytes().as_slice(),
|
||||
hash
|
||||
)
|
||||
.execute(&self.pool)
|
||||
.await?;
|
||||
|
||||
Ok(Ok(userid))
|
||||
}
|
||||
|
||||
pub async fn create_activation_token(
|
||||
&self,
|
||||
token: String,
|
||||
password: String,
|
||||
) -> Result<Result<Uuid, error::AccountRegisterError>> {
|
||||
if !self.check_activation_token(&token).await? {
|
||||
return Ok(Err(AccountRegisterError::InvalidToken));
|
||||
}
|
||||
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
|
||||
let hash = Argon2::default()
|
||||
.hash_password(password.as_bytes(), &salt)
|
||||
.map_err(|_| anyhow::Error::msg("Failed to hash the password"))?
|
||||
.to_string();
|
||||
|
||||
let userid = Uuid::new_v4();
|
||||
|
||||
sqlx::query!(
|
||||
r#"INSERT INTO Users VALUES (?, ?, 0);"#,
|
||||
userid.as_bytes().as_slice(),
|
||||
hash
|
||||
)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
pub enum Permission {
|
||||
GenerateInviteTokens,
|
||||
PromoteUsers,
|
||||
}
|
||||
|
||||
impl Permission {
|
||||
pub fn as_u16(&self) -> u16 {
|
||||
match self {
|
||||
Permission::GenerateInviteTokens => 1,
|
||||
Permission::PromoteUsers => 1 << 1,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
use crate::backend::db_structures::UsersRow;
|
||||
use crate::backend::{permissions::Permission, Backend};
|
||||
use anyhow::Result;
|
||||
use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub struct User {
|
||||
uuid: Uuid,
|
||||
password: String,
|
||||
permissions: u16,
|
||||
}
|
||||
|
||||
impl TryFrom<UsersRow> for User {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(value: UsersRow) -> std::result::Result<Self, Self::Error> {
|
||||
Ok(Self {
|
||||
uuid: Uuid::from_str(value.userid.as_str())?,
|
||||
password: value.password,
|
||||
permissions: value.permissions,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub fn has_permission(&self, permission: Permission) -> bool {
|
||||
(self.permissions & permission.as_u16()) > 0
|
||||
}
|
||||
|
||||
async fn flush(&self, backend: &Backend) -> Result<()> {
|
||||
sqlx::query!(
|
||||
r#"UPDATE Users SET password = ?, permissions = ? WHERE userid = ?;"#,
|
||||
self.password,
|
||||
self.permissions,
|
||||
self.uuid.as_bytes().as_slice()
|
||||
)
|
||||
.execute(&backend.pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue