use super::rpc_methods::*; use crate::database::Database; use crate::server::messages::{ CreatePermissionsRequest, CreateRoleRequest, ErrorMessage, GetPermissionsRequest, InfoEntry, TokenRequest, }; use crate::utils::get_user_id_from_token; use msgrpc::message::Message; use msgrpc::server::RpcServer; use rmp_serde::Deserializer; use scheduled_thread_pool::ScheduledThreadPool; use serde::Deserialize; use std::collections::HashMap; use std::sync::Arc; use std::thread::Builder; const RPC_SERVER_ADDRESS: &str = "RPC_SERVER_ADDRESS"; const DEFAULT_SERVER_ADDRESS: &str = "127.0.0.1:5555"; /// The RPC server that provides an interface /// for applications to validate request tokens /// and request the assigned roles pub struct UserRpcServer { database: Database, } type RpcResult = Result; impl UserRpcServer { pub fn new(database: &Database) -> Self { Self { database: Database::clone(database), } } /// Stats the user rpc server with 2 x num-cpus threads. pub fn start(&self) { let listen_address = dotenv::var(RPC_SERVER_ADDRESS).unwrap_or(DEFAULT_SERVER_ADDRESS.to_string()); log::info!("Starting RPC-Server..."); let mut server = RpcServer::new(listen_address.clone()); let receiver = Arc::clone(&server.receiver); Builder::new() .name("tcp-receiver".to_string()) .spawn(move || { server.start().unwrap(); }) .unwrap(); let pool = ScheduledThreadPool::new(num_cpus::get()); log::info!("RPC-Server running on {}", listen_address); while let Ok(h) = receiver.lock().unwrap().recv() { let database = Database::clone(&self.database); log::trace!("Scheduling message for execution in pool"); pool.execute(move || { let mut handler = h.lock().unwrap(); log::debug!("Received message {:?}", handler.message); let response = match handler.message.method { INFO => Self::handle_info(), GET_ROLES => Self::handle_get_roles(database, &handler.message.data), VALIDATE_TOKEN => Self::handle_validate_token(database, &handler.message.data), GET_ROLE_PERMISSIONS => { Self::handle_get_permissions(database, &handler.message.data) } CREATE_ROLE => Self::handle_create_role(database, &handler.message.data), CREATE_PERMISSION => { Self::handle_create_permissions(database, &handler.message.data) } _ => Err(ErrorMessage::new("Invalid Method".to_string())), } .unwrap_or_else(|e| Message::new_with_serialize(ERROR, e)); log::debug!("Responding with message {:?}", &response); handler.done(response); }); } } /// Handles the validation of request tokens fn handle_validate_token(database: Database, data: &Vec) -> RpcResult { log::trace!("Validating token."); let message = TokenRequest::deserialize(&mut Deserializer::new(&mut data.as_slice())) .map_err(|e| ErrorMessage::new(e.to_string()))?; let valid = database .users .validate_request_token(&message.token) .unwrap_or((false, -1)); log::trace!("Serializing..."); let data = rmp_serde::to_vec(&valid).map_err(|e| ErrorMessage::new(e.to_string()))?; Ok(Message::new(VALIDATE_TOKEN, data)) } /// Handles a INFO message that returns all valid methods of the rpc sserver fn handle_info() -> RpcResult { log::trace!("Get Info"); Ok(Message::new_with_serialize( INFO, vec![ InfoEntry::new("info", INFO, "Shows this entry", ""), InfoEntry::new( "validate token", VALIDATE_TOKEN, "Validates a request token", "{token: String}", ), InfoEntry::new( "get roles", GET_ROLES, "Returns the roles the user is assigned to", "{token: String}", ), InfoEntry::new( "get permissions", GET_ROLE_PERMISSIONS, "Returns all permissions the given roles are assigned to", "{roles: [i32]}", ), InfoEntry::new( "create role", CREATE_ROLE, "Creates a new role with the given permissions", "{name: String, description: String, permissions: [i32]}", ), InfoEntry::new( "create permissions", CREATE_PERMISSION, "Creates all given permissions if they don't exist.", "{permissions: [{name: String, description: String}]}", ), ], )) } /// Returns all permissions of a role fn handle_get_permissions(database: Database, data: &Vec) -> RpcResult { log::trace!("Get Permissions"); let message = GetPermissionsRequest::deserialize(&mut Deserializer::new(&mut data.as_slice())) .map_err(|e| ErrorMessage::new(e.to_string()))?; let mut response_data = HashMap::new(); for role_id in message.roles { let permissions = database.role_permission.by_role(role_id)?; response_data.insert(role_id.to_string(), permissions); } Ok(Message::new_with_serialize( GET_ROLE_PERMISSIONS, response_data, )) } /// Returns all roles of a user fn handle_get_roles(database: Database, data: &Vec) -> RpcResult { log::trace!("Get Roles"); let message = TokenRequest::deserialize(&mut Deserializer::new(&mut data.as_slice())) .map_err(|e| ErrorMessage::new(e.to_string()))?; if !database .users .validate_request_token(&message.token) .unwrap_or((false, -1)) .0 { return Err(ErrorMessage::new("Invalid request token".to_string())); } let user_id = get_user_id_from_token(&message.token) .ok_or(ErrorMessage::new("Invalid request token".to_string()))?; let response_data = database.user_roles.by_user(user_id)?; Ok(Message::new_with_serialize(GET_ROLES, response_data)) } /// Handles the requests for creating new roles fn handle_create_role(database: Database, data: &Vec) -> RpcResult { log::trace!("Create Role"); let message = CreateRoleRequest::deserialize(&mut Deserializer::new(&mut data.as_slice())) .map_err(|e| ErrorMessage::new(e.to_string()))?; let role = database .roles .create_role(message.name, message.description, message.permissions)?; Ok(Message::new_with_serialize(CREATE_ROLE, role)) } /// Handles the request for creating new permissions. fn handle_create_permissions(database: Database, data: &Vec) -> RpcResult { log::trace!("Create Permission"); let message = CreatePermissionsRequest::deserialize(&mut Deserializer::new(&mut data.as_slice())) .map_err(|e| ErrorMessage::new(e.to_string()))?; let permissions = database .permissions .create_permissions(message.permissions)?; Ok(Message::new_with_serialize(CREATE_PERMISSION, permissions)) } }