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 struct UsersRow {
|
||||||
pub userid: String,
|
pub userid: String,
|
||||||
pub password: String,
|
pub password: String,
|
||||||
|
pub permissions: u16,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
mod db_structures;
|
mod db_structures;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
mod permissions;
|
||||||
|
mod user;
|
||||||
|
|
||||||
use crate::backend::error::AccountRegisterError;
|
use crate::backend::error::AccountRegisterError;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
@ -11,6 +13,7 @@ use argon2::{
|
||||||
use db_structures::{ActivationTokensRow, UsersRow};
|
use db_structures::{ActivationTokensRow, UsersRow};
|
||||||
use log::info;
|
use log::info;
|
||||||
use sqlx::{types::chrono::Utc, MySqlPool};
|
use sqlx::{types::chrono::Utc, MySqlPool};
|
||||||
|
use user::User;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -24,8 +27,9 @@ impl Backend {
|
||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"CREATE TABLE IF NOT EXISTS Users (
|
r#"CREATE TABLE IF NOT EXISTS Users (
|
||||||
userid UUID NOT NULL PRIMARY KEY,
|
userid UUID NOT NULL PRIMARY KEY,
|
||||||
password VARCHAR(128) NOT NULL
|
password VARCHAR(128) NOT NULL,
|
||||||
|
permissions SMALLINT UNSIGNED NOT NULL
|
||||||
);"#
|
);"#
|
||||||
)
|
)
|
||||||
.execute(&pool)
|
.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!(
|
match sqlx::query_as!(
|
||||||
UsersRow,
|
UsersRow,
|
||||||
r#"SELECT * FROM Users WHERE userid = ?;"#,
|
r#"SELECT * FROM Users WHERE userid = ?;"#,
|
||||||
|
@ -101,9 +105,9 @@ impl Backend {
|
||||||
{
|
{
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
sqlx::Error::RowNotFound => Ok(None),
|
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();
|
let userid = Uuid::new_v4();
|
||||||
|
|
||||||
sqlx::query!(
|
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(),
|
userid.as_bytes().as_slice(),
|
||||||
hash
|
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