diff --git a/bffhd/authorization/mod.rs b/bffhd/authorization/mod.rs index 0055cbb..e34547e 100644 --- a/bffhd/authorization/mod.rs +++ b/bffhd/authorization/mod.rs @@ -1,34 +1,33 @@ use std::sync::Arc; use crate::authorization::permissions::Permission; use crate::authorization::roles::Role; +use crate::Users; use crate::users::User; pub mod permissions; pub mod roles; struct Inner { - + users: Users, } impl Inner { - pub fn new() -> Self { - Self {} + pub fn new(users: Users) -> Self { + Self { users } } } #[derive(Clone)] pub struct AuthorizationHandle { - inner: Arc, + users: Users, } impl AuthorizationHandle { - pub fn new() -> Self { - Self { - inner: Arc::new(Inner::new()) - } + pub fn new(users: Users) -> Self { + Self { users } } pub fn get_user_roles(&self, uid: impl AsRef) -> Option> { - unimplemented!(); + let user = self.users.get_user(uid.as_ref())?; Some([]) } diff --git a/bffhd/resources/mod.rs b/bffhd/resources/mod.rs index ea648d0..2f098a4 100644 --- a/bffhd/resources/mod.rs +++ b/bffhd/resources/mod.rs @@ -94,15 +94,13 @@ impl Resource { } fn set_state(&self, state: MachineState) { - + self.inner.set_state(state) } fn set_status(&self, state: Status) { - unimplemented!() - } - - fn set_previous_user(&self, user: User) { - unimplemented!() + let old = self.inner.get_state(); + let new = MachineState { state, .. old }; + self.set_state(new); } pub async fn try_update(&self, session: SessionHandle, new: Status) { @@ -168,7 +166,7 @@ impl Resource { } pub async fn force_set(&self, new: Status) { - unimplemented!() + self.set_status(new); } pub fn visible(&self, session: &SessionHandle) -> bool { diff --git a/bffhd/users/mod.rs b/bffhd/users/mod.rs index daa4930..a2714e2 100644 --- a/bffhd/users/mod.rs +++ b/bffhd/users/mod.rs @@ -14,20 +14,22 @@ * along with this program. If not, see . */ -use std::collections::HashMap; +use anyhow::Context; +use lmdb::Environment; +use once_cell::sync::OnceCell; use rkyv::{Archive, Deserialize, Infallible, Serialize}; +use std::collections::HashMap; use std::ops::Deref; use std::path::Path; use std::sync::Arc; -use anyhow::Context; -use lmdb::Environment; pub mod db; pub use crate::authentication::db::PassDB; use crate::authorization::roles::{Role, RoleIdentifier}; -use crate::UserDB; +use crate::db::LMDBorrow; use crate::users::db::UserData; +use crate::UserDB; #[derive( Clone, @@ -53,28 +55,37 @@ impl User { pub fn get_username(&self) -> &str { self.id.as_str() } - - pub fn get_roles(&self) -> impl IntoIterator { - unimplemented!(); - [] - } } -pub struct Inner { - userdb: UserDB, - //passdb: PassDB, -} +static USERDB: OnceCell = OnceCell::new(); -#[derive(Clone)] +#[derive(Copy, Clone)] +#[repr(transparent)] pub struct Users { - inner: Arc + userdb: &'static UserDB, } impl Users { pub fn new(env: Arc) -> anyhow::Result { - let userdb = unsafe { UserDB::create(env.clone()).unwrap() }; - //let passdb = unsafe { PassDB::create(env).unwrap() }; - Ok(Self { inner: Arc::new(Inner { userdb }) }) + let span = tracing::debug_span!("users", ?env, "Creating Users handle"); + let _guard = span.enter(); + + let userdb = USERDB + .get_or_try_init(|| { + tracing::debug!("Global resource not yet initialized, initializing…"); + unsafe { UserDB::create(env.clone()) } + }) + .context("Failed to open userdb")?; + + Ok(Self { userdb }) + } + + pub fn get_user(&self, uid: &str) -> Option { + tracing::trace!(uid, "Looking up user"); + self.userdb + .get(uid) + .unwrap() + .map(|user| Deserialize::::deserialize(user.deref(), &mut Infallible).unwrap()) } pub fn load_file>(&self, path: P) -> anyhow::Result<()> { @@ -82,22 +93,27 @@ impl Users { let mut map: HashMap = toml::from_slice(&f)?; for (uid, mut userdata) in map { - userdata.passwd = userdata.passwd.map(|pw| if !pw.starts_with("$argon2") { - let config = argon2::Config::default(); - let salt: [u8; 16] = rand::random(); - let hash = argon2::hash_encoded(pw.as_bytes(), &salt, &config) - .expect(&format!("Failed to hash password for {}: ", uid)); - tracing::debug!("Hashed pw for {} to {}", uid, hash); + userdata.passwd = userdata.passwd.map(|pw| { + if !pw.starts_with("$argon2") { + let config = argon2::Config::default(); + let salt: [u8; 16] = rand::random(); + let hash = argon2::hash_encoded(pw.as_bytes(), &salt, &config) + .expect(&format!("Failed to hash password for {}: ", uid)); + tracing::debug!("Hashed pw for {} to {}", uid, hash); - hash - } else { - pw + hash + } else { + pw + } }); - let user = db::User { id: uid.clone(), userdata }; + let user = db::User { + id: uid.clone(), + userdata, + }; tracing::trace!(%uid, ?user, "Storing user object"); - self.inner.userdb.put(uid.as_str(), &user); + self.userdb.put(uid.as_str(), &user); } Ok(()) } -} \ No newline at end of file +}