Mercurial > lbo > hg > analyrics
view src/configdb.rs @ 80:d3368a7142ef default tip
Make analyrics build again and add Cargo.lock
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sat, 27 Apr 2024 20:34:05 +0200 |
parents | fd0237049be0 |
children |
line wrap: on
line source
use crate::db::PoolType; use anyhow::Error; use log::warn; use rand::distributions::{Alphanumeric, DistString}; use rocket_db_pools::sqlx::{Executor, Row, Sqlite}; use rocket_db_pools::Database; use sqlx::prelude::FromRow; use sqlx::Acquire; fn generate_salt() -> String { Alphanumeric.sample_string(&mut rand::thread_rng(), 16) } // TO DO: use other databases? #[derive(Database)] #[database("sqlite_main")] pub struct ConfigDB(pub PoolType); #[derive(Default, Clone, Debug, FromRow)] pub struct UserRecord { pub name: String, pub tz_offset: i64, } pub struct ConfigDBSession<'p, DB: sqlx::Database>(pub &'p mut sqlx::pool::PoolConnection<DB>); impl<'p> ConfigDBSession<'p, Sqlite> { pub async fn check_user_password<S0: AsRef<str>, S1: AsRef<str>>( &mut self, user: S0, password: S1, ) -> Result<bool, Error> { // TODO: salt passwords. let salt: String = match sqlx::query("SELECT salt FROM users WHERE username = ? LIMIT 1;") .bind(user.as_ref()) .fetch_one(self.0.acquire().await?) .await { Ok(r) => r.get(0), Err(e) => { warn!("Error querying salt: {}", e); return Ok(false); } }; let pwdhash = sha256::digest(format!("{}{}", salt, password.as_ref())); let q = sqlx::query("SELECT username FROM users WHERE username = ? AND password_hash = ?;") .bind(user.as_ref()) .bind(pwdhash); let result = self.0.fetch_all(q).await?; Ok(result.len() == 1) } pub async fn get_user_details(&mut self, user: &str) -> Result<UserRecord, Error> { let entry = sqlx::query("SELECT name, tz_offset FROM users WHERE username = ? LIMIT 1") .bind(user) .fetch_one(self.0.acquire().await?) .await?; Ok(UserRecord::from_row(&entry)?) } pub async fn update_user_password<S0: AsRef<str>, S1: AsRef<str>, S2: AsRef<str>>( &mut self, user: S0, oldpass: S1, newpass: S2, ) -> Result<(), Error> { if !self.check_user_password(user, oldpass).await? { anyhow::bail!("User not authorized (wrong password?)") } // Old password is ok. let salt = generate_salt(); let newpass_hash = sha256::digest(format!("{}{}", salt, newpass.as_ref())); sqlx::query("UPDATE users SET salt = ?, password_hash = ?;") .bind(salt) .bind(newpass_hash) .execute(self.0.acquire().await?) .await?; Ok(()) } pub async fn update_user_tz<S0: AsRef<str>>( &mut self, user: S0, tz_offset: i64, ) -> Result<(), Error> { if sqlx::query("SELECT username FROM users WHERE username = ?") .bind(user.as_ref()) .fetch_all(self.0.acquire().await?) .await? .len() != 1 { anyhow::bail!("User not found, or duplicate user {}", user.as_ref()) } sqlx::query("UPDATE users SET tz_offset = ? WHERE username = ?") .bind(tz_offset) .bind(user.as_ref()) .execute(self.0.acquire().await?) .await?; Ok(()) } pub async fn is_admin<S0: AsRef<str>>(&mut self, user: S0) -> Result<bool, Error> { Ok(sqlx::query("SELECT is_admin FROM users JOIN permissions ON (users.id = permissions.user_id) WHERE username = ?") .bind(user.as_ref()) .fetch_one(self.0.acquire().await?) .await? .get(0)) } }