use anyhow::Error; use thiserror::Error; use tokio::{fs::File, io::AsyncReadExt}; use crate::message::{AuthenticatedInstance, Message, MessageHandler, NetworkMessage, State}; use giterated_models::{ messages::authentication::{ AuthenticationTokenRequest, AuthenticationTokenResponse, RegisterAccountRequest, TokenExtensionRequest, }, model::authenticated::InstanceAuthenticator, }; use super::wrapper::ConnectionState; pub async fn authentication_handle( message_type: &str, message: &NetworkMessage, state: &ConnectionState, ) -> Result { match message_type { "giterated_models::messages::authentication::RegisterAccountRequest" => { register_account_request .handle_message(&message, state) .await?; Ok(true) } "giterated_models::messages::authentication::AuthenticationTokenRequest" => { authentication_token_request .handle_message(&message, state) .await?; Ok(true) } "giterated_models::messages::authentication::TokenExtensionRequest" => { token_extension_request .handle_message(&message, state) .await?; Ok(true) } _ => Ok(false), } } async fn register_account_request( State(connection_state): State, Message(request): Message, instance: AuthenticatedInstance, ) -> Result<(), AuthenticationConnectionError> { if *instance.inner() != connection_state.instance { return Err(AuthenticationConnectionError::SameInstance); } let mut user_backend = connection_state.user_backend.lock().await; let response = user_backend .register(request.clone()) .await .map_err(|e| AuthenticationConnectionError::Registration(e))?; drop(user_backend); connection_state .send(response) .await .map_err(|e| AuthenticationConnectionError::Sending(e))?; Ok(()) } async fn authentication_token_request( State(connection_state): State, Message(request): Message, instance: AuthenticatedInstance, ) -> Result<(), AuthenticationConnectionError> { if request.instance != connection_state.instance { // We need to perform the authentication request on behalf of // the user. TODO: Oauth-style flow let mut connections = connection_state.instance_connections.lock().await; let issued_for = instance.inner().clone(); let connection = connections.get_or_open(&request.instance).unwrap(); let private_key = { let mut file = File::open( connection_state.config["giterated"]["keys"]["private"] .as_str() .unwrap(), ) .await .unwrap(); let mut key = String::new(); file.read_to_string(&mut key).await.unwrap(); key }; info!("Our private key: {}", private_key); let authenticator = InstanceAuthenticator { instance: connection_state.instance.clone(), private_key, }; let response = giterated_api::request::request_local(request) .authenticate(authenticator) .execute_expect::(&connection) .await .unwrap(); drop(connection); connection_state .send(response) .await .map_err(|e| AuthenticationConnectionError::Sending(e))?; return Ok(()); } let mut user_backend = connection_state.user_backend.lock().await; let response = user_backend .login(instance.inner(), request) .await .map_err(|e| AuthenticationConnectionError::TokenIssuance(e))?; connection_state .send(response) .await .map_err(|e| AuthenticationConnectionError::Sending(e))?; Ok(()) } async fn token_extension_request( State(connection_state): State, Message(request): Message, instance: AuthenticatedInstance, ) -> Result<(), AuthenticationConnectionError> { let issued_for = instance.inner().clone(); let mut token_granter = connection_state.auth_granter.lock().await; let response = token_granter .extension_request(&issued_for, &connection_state.key_cache, request.token) .await .map_err(|e| AuthenticationConnectionError::TokenIssuance(e))?; connection_state .send(response) .await .map_err(|e| AuthenticationConnectionError::Sending(e))?; Ok(()) } #[derive(Debug, Error)] pub enum AuthenticationConnectionError { #[error("the request was invalid")] InvalidRequest, #[error("request must be from the same instance")] SameInstance, #[error("issue during registration {0}")] Registration(Error), #[error("sending error")] Sending(Error), #[error("error issuing token")] TokenIssuance(Error), }