use api::users_capnp::users; use capnp::capability::Promise; use capnp_rpc::pry; use tracing::Span; use crate::capnp::user::User; use crate::session::SessionHandle; use crate::users::{db, UserRef}; const TARGET: &str = "bffh::api::usersystem"; #[derive(Clone)] pub struct Users { span: Span, session: SessionHandle, } impl Users { pub fn new(session: SessionHandle) -> Self { let span = tracing::info_span!(target: TARGET, "UserSystem",); Self { span, session } } } impl users::Server for Users { fn list( &mut self, _: users::ListParams, mut result: users::ListResults, ) -> Promise<(), ::capnp::Error> { let _guard = self.span.enter(); let _span = tracing::trace_span!(target: TARGET, "getUserList",).entered(); tracing::trace!("method call"); let userdb = self.session.users.into_inner(); let users = pry!(userdb .get_all() .map_err(|e| capnp::Error::failed(format!("UserDB error: {:?}", e)))); let mut builder = result.get().init_users(users.len() as u32); for (i, (id, userdata)) in users.into_iter().enumerate() { let user = db::User { id, userdata }; builder.reborrow().set(i as u32, User::fill(&self.session, user)); } tracing::trace!("method return"); Promise::ok(()) } fn add_user( &mut self, params: users::AddUserParams, mut result: users::AddUserResults, ) -> Promise<(), ::capnp::Error> { let _guard = self.span.enter(); let _span = tracing::trace_span!(target: TARGET, "addUserFallible").entered(); let params = pry!(params.get()); let username = pry!(params.get_username()); let password = pry!(params.get_password()); // FIXME: saslprep passwords & usernames before storing them tracing::trace!( params.username = username, params.password = "", "method call" ); let mut builder = result.get(); if !username.is_empty() && !password.is_empty() { if self.session.users.get_user(username).is_none() { let user = db::User::new_with_plain_pw(username, password); self.session.users.put_user(username, &user); builder.set_user(capnp_rpc::new_client(User::fill(&self.session, user))); } else { let mut builder = builder.init_error(); builder.set_exists(); tracing::warn!("Failed to add user: Username taken"); } } else { if username.is_empty() { let mut builder = builder.init_error(); builder.set_username_invalid(); tracing::warn!("Failed to add user: Username empty"); } else if password.is_empty() { let mut builder = builder.init_error(); builder.set_password_invalid(); tracing::warn!("Failed to add user: Password empty"); } } tracing::trace!("method return"); Promise::ok(()) } fn remove_user( &mut self, params: users::RemoveUserParams, _: users::RemoveUserResults, ) -> Promise<(), ::capnp::Error> { let _guard = self.span.enter(); let _span = tracing::trace_span!(target: TARGET, "removeUser",).entered(); let who: &str = pry!(pry!(pry!(params.get()).get_user()).get_username()); tracing::trace!(params.user = who, "method call"); if let Err(e) = self.session.users.del_user(who) { tracing::warn!("Failed to delete user: {:?}", e); } else { tracing::info!("Deleted user {}", who); } tracing::trace!("method return"); Promise::ok(()) } }