diff --git a/giterated-daemon/src/backend/git.rs b/giterated-daemon/src/backend/git.rs index c75935b..6bf1493 100644 --- a/giterated-daemon/src/backend/git.rs +++ b/giterated-daemon/src/backend/git.rs @@ -295,6 +295,7 @@ impl RepositoryBackend for GitBackend { ) -> Result, Error> { Ok(match name { "description" => unsafe { + info!("Description"); AnyValue::from_raw( self.get_setting(repository, RepositoryDescription::name()) .await? diff --git a/giterated-daemon/src/connection/authentication.rs b/giterated-daemon/src/connection/authentication.rs deleted file mode 100644 index 5a1c467..0000000 --- a/giterated-daemon/src/connection/authentication.rs +++ /dev/null @@ -1,172 +0,0 @@ -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), -} diff --git a/giterated-daemon/src/connection/forwarded.rs b/giterated-daemon/src/connection/forwarded.rs deleted file mode 100644 index c53ce9c..0000000 --- a/giterated-daemon/src/connection/forwarded.rs +++ /dev/null @@ -1,58 +0,0 @@ -use futures_util::{SinkExt, StreamExt}; -use giterated_api::DaemonConnectionPool; -use giterated_models::{ - messages::error::ConnectionError, model::authenticated::AuthenticatedPayload, -}; - -use tokio_tungstenite::tungstenite::Message; - -pub async fn wrap_forwarded(pool: &DaemonConnectionPool, message: AuthenticatedPayload) -> Message { - let connection = pool.get().await; - - let mut connection = match connection { - Ok(connection) => connection, - Err(e) => { - return Message::Binary(serde_json::to_vec(&ConnectionError(e.to_string())).unwrap()) - } - }; - - let send_result = connection - .send(Message::Binary(serde_json::to_vec(&message).unwrap())) - .await; - - if let Err(e) = send_result { - return Message::Binary(serde_json::to_vec(&ConnectionError(e.to_string())).unwrap()); - } - - loop { - let message = connection.next().await; - - match message { - Some(Ok(message)) => { - match message { - Message::Binary(payload) => return Message::Binary(payload), - Message::Ping(_) => { - let _ = connection.send(Message::Pong(vec![])).await; - continue; - } - Message::Close(_) => { - return Message::Binary( - String::from("The instance you wanted to talk to hung up on me :(") - .into_bytes(), - ) - } - _ => continue, - }; - } - Some(Err(e)) => { - return Message::Binary( - serde_json::to_vec(&ConnectionError(e.to_string())).unwrap(), - ) - } - _ => { - info!("Unhandled"); - continue; - } - } - } -} diff --git a/giterated-daemon/src/connection/handshake.rs b/giterated-daemon/src/connection/handshake.rs deleted file mode 100644 index a86b40c..0000000 --- a/giterated-daemon/src/connection/handshake.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::sync::atomic::Ordering; - -use anyhow::Error; -use giterated_models::messages::handshake::{ - HandshakeFinalize, HandshakeResponse, InitiateHandshake, -}; -use semver::Version; - -use crate::{ - message::{HandshakeMessage, MessageHandler, NetworkMessage, State}, - version, -}; - -use super::{wrapper::ConnectionState, HandlerUnhandled}; - -pub async fn handshake_handle( - message: &NetworkMessage, - state: &ConnectionState, -) -> Result<(), Error> { - if initiate_handshake - .handle_message(&message, state) - .await - .is_ok() - { - Ok(()) - } else if handshake_response - .handle_message(&message, state) - .await - .is_ok() - { - Ok(()) - } else if handshake_finalize - .handle_message(&message, state) - .await - .is_ok() - { - Ok(()) - } else { - Err(Error::from(HandlerUnhandled)) - } -} - -async fn initiate_handshake( - HandshakeMessage(_initiation): HandshakeMessage, - State(connection_state): State, -) -> Result<(), HandshakeError> { - info!("meow!"); - connection_state - .send(HandshakeResponse { - identity: connection_state.instance.clone(), - version: version(), - }) - .await - .map_err(|e| HandshakeError::SendError(e))?; - - Ok(()) - // if !validate_version(&initiation.version) { - // error!( - // "Version compatibility failure! Our Version: {}, Their Version: {}", - // Version::from_str(&std::env::var("CARGO_PKG_VERSION").unwrap()).unwrap(), - // initiation.version - // ); - - // connection_state - // .send(HandshakeFinalize { success: false }) - // .await - // .map_err(|e| HandshakeError::SendError(e))?; - - // Ok(()) - // } else { - // connection_state - // .send(HandshakeResponse { - // identity: connection_state.instance.clone(), - // version: version(), - // }) - // .await - // .map_err(|e| HandshakeError::SendError(e))?; - - // Ok(()) - // } -} - -async fn handshake_response( - HandshakeMessage(_initiation): HandshakeMessage, - State(connection_state): State, -) -> Result<(), HandshakeError> { - connection_state - .send(HandshakeFinalize { success: true }) - .await - .map_err(|e| HandshakeError::SendError(e))?; - - Ok(()) - // if !validate_version(&response.version) { - // error!( - // "Version compatibility failure! Our Version: {}, Their Version: {}", - // Version::from_str(&std::env::var("CARGO_PKG_VERSION").unwrap()).unwrap(), - // response.version - // ); - - // connection_state - // .send(HandshakeFinalize { success: false }) - // .await - // .map_err(|e| HandshakeError::SendError(e))?; - - // Ok(()) - // } else { - // connection_state - // .send(HandshakeFinalize { success: true }) - // .await - // .map_err(|e| HandshakeError::SendError(e))?; - - // Ok(()) - // } -} - -async fn handshake_finalize( - HandshakeMessage(_finalize): HandshakeMessage, - State(connection_state): State, -) -> Result<(), HandshakeError> { - connection_state.handshaked.store(true, Ordering::SeqCst); - - connection_state - .send(HandshakeFinalize { success: true }) - .await - .map_err(|e| HandshakeError::SendError(e))?; - - Ok(()) - // if !finalize.success { - // error!("Error during handshake, aborting connection"); - // return Err(Error::from(ConnectionError::Shutdown).into()); - // } else { - // connection_state.handshaked.store(true, Ordering::SeqCst); - - // connection_state - // .send(HandshakeFinalize { success: true }) - // .await - // .map_err(|e| HandshakeError::SendError(e))?; - - // Ok(()) - // } -} - -#[derive(Debug, thiserror::Error)] -pub enum HandshakeError { - #[error("version mismatch during handshake, ours: {0}, theirs: {1}")] - VersionMismatch(Version, Version), - #[error("while sending message: {0}")] - SendError(Error), - #[error("{0}")] - Other(#[from] Error), -} diff --git a/giterated-daemon/src/connection/repository.rs b/giterated-daemon/src/connection/repository.rs deleted file mode 100644 index 8a872e7..0000000 --- a/giterated-daemon/src/connection/repository.rs +++ /dev/null @@ -1,141 +0,0 @@ -use anyhow::Error; - -use crate::{ - backend::git::GitBackendError, - message::{AuthenticatedUser, Message, MessageHandler, NetworkMessage, State}, -}; -use giterated_models::messages::repository::{ - RepositoryCreateRequest, RepositoryFileInspectRequest, RepositoryInfoRequest, - RepositoryIssueLabelsRequest, RepositoryIssuesCountRequest, RepositoryIssuesRequest, -}; - -use super::wrapper::ConnectionState; - -pub async fn repository_handle( - message_type: &str, - message: &NetworkMessage, - state: &ConnectionState, -) -> Result { - match message_type { - "giterated_models::messages::repository::RepositoryCreateRequest" => { - create_repository.handle_message(&message, state).await?; - - Ok(true) - } - "giterated_models::messages::repository::RepositoryFileInspectRequest" => { - repository_file_inspect - .handle_message(&message, state) - .await?; - - Ok(true) - } - "giterated_models::messages::repository::RepositoryInfoRequest" => { - repository_info.handle_message(&message, state).await?; - - Ok(true) - } - "giterated_models::messages::repository::RepositoryIssuesCountRequest" => { - issues_count.handle_message(&message, state).await?; - - Ok(true) - } - "giterated_models::messages::repository::RepositoryIssueLabelsRequest" => { - issue_labels.handle_message(&message, state).await?; - - Ok(true) - } - "giterated_models::messages::repository::RepositoryIssuesRequest" => { - issues.handle_message(&message, state).await?; - - Ok(true) - } - _ => Ok(false), - } -} - -async fn create_repository( - Message(request): Message, - State(connection_state): State, - AuthenticatedUser(user): AuthenticatedUser, -) -> Result<(), RepositoryError> { - let mut repository_backend = connection_state.repository_backend.lock().await; - let response = repository_backend - .create_repository(&user, &request) - .await?; - - drop(repository_backend); - - connection_state.send(response).await?; - - Ok(()) -} - -async fn repository_file_inspect( - Message(request): Message, - State(connection_state): State, - user: Option, -) -> Result<(), RepositoryError> { - let user = user.map(|u| u.0); - - let mut repository_backend = connection_state.repository_backend.lock().await; - let response = repository_backend - .repository_file_inspect(user.as_ref(), &request) - .await?; - - drop(repository_backend); - - connection_state.send(response).await?; - - Ok(()) -} - -async fn repository_info( - Message(request): Message, - State(connection_state): State, - user: Option, -) -> Result<(), RepositoryError> { - let user = user.map(|u| u.0); - - let mut repository_backend = connection_state.repository_backend.lock().await; - let response = repository_backend - .repository_info(user.as_ref(), &request) - .await?; - - drop(repository_backend); - - connection_state.send(response).await?; - - Ok(()) -} - -async fn issues_count( - Message(_request): Message, - State(_connection_state): State, - _user: Option, -) -> Result<(), RepositoryError> { - unimplemented!(); -} - -async fn issue_labels( - Message(_request): Message, - State(_connection_state): State, - _user: Option, -) -> Result<(), RepositoryError> { - unimplemented!(); -} - -async fn issues( - Message(_request): Message, - State(_connection_state): State, - _user: Option, -) -> Result<(), RepositoryError> { - unimplemented!(); -} - -#[derive(Debug, thiserror::Error)] -pub enum RepositoryError { - #[error("{0}")] - GitBackendError(#[from] GitBackendError), - #[error("{0}")] - Other(#[from] Error), -} diff --git a/giterated-daemon/src/connection/user.rs b/giterated-daemon/src/connection/user.rs deleted file mode 100644 index c3b5691..0000000 --- a/giterated-daemon/src/connection/user.rs +++ /dev/null @@ -1,182 +0,0 @@ -use anyhow::Error; -use giterated_models::{ - messages::user::{ - UserBioRequest, UserDisplayImageRequest, UserDisplayNameRequest, UserRepositoriesRequest, - UserRepositoriesResponse, UserSettingsRequest, UserSettingsResponse, - UserWriteSettingsRequest, UserWriteSettingsResponse, - }, - model::user::User, -}; - -use crate::message::{AuthenticatedUser, Message, MessageHandler, NetworkMessage, State}; - -use super::wrapper::ConnectionState; - -pub async fn user_handle( - message_type: &str, - message: &NetworkMessage, - state: &ConnectionState, -) -> Result { - match message_type { - "giterated_models::messages::user::UserDisplayNameRequest" => { - display_name.handle_message(&message, state).await?; - - Ok(true) - } - "giterated_models::messages::user::UserDisplayImageRequest" => { - display_image.handle_message(&message, state).await?; - - Ok(true) - } - "giterated_models::messages::user::UserBioRequest" => { - bio.handle_message(&message, state).await?; - - Ok(true) - } - "giterated_models::messages::user::UserRepositoriesRequest" => { - repositories.handle_message(&message, state).await?; - - Ok(true) - } - "giterated_models::messages::user::UserSettingsRequest" => { - user_settings.handle_message(&message, state).await?; - - Ok(true) - } - "giterated_models::messages::user::UserWriteSettingsRequest" => { - write_user_settings.handle_message(&message, state).await?; - - Ok(true) - } - _ => Ok(false), - } -} - -async fn display_name( - Message(request): Message, - State(connection_state): State, -) -> Result<(), UserError> { - let mut user_backend = connection_state.user_backend.lock().await; - let response = user_backend.display_name(request.clone()).await?; - - drop(user_backend); - - connection_state.send(response).await?; - - Ok(()) -} - -async fn display_image( - Message(request): Message, - State(connection_state): State, -) -> Result<(), UserError> { - let mut user_backend = connection_state.user_backend.lock().await; - let response = user_backend.display_image(request.clone()).await?; - - drop(user_backend); - - connection_state.send(response).await?; - - Ok(()) -} - -async fn bio( - Message(request): Message, - State(connection_state): State, -) -> Result<(), UserError> { - let mut user_backend = connection_state.user_backend.lock().await; - let response = user_backend.bio(request.clone()).await?; - - drop(user_backend); - - connection_state.send(response).await?; - - Ok(()) -} - -async fn repositories( - Message(request): Message, - State(connection_state): State, - requesting_user: Option, -) -> Result<(), UserError> { - let requesting_user = requesting_user.map(|u| u.0); - - let mut repository_backend = connection_state.repository_backend.lock().await; - let repositories = repository_backend - .repositories_for_user(requesting_user.as_ref(), &request.user) - .await; - - let repositories = match repositories { - Ok(repositories) => repositories, - Err(err) => { - error!("Error handling request: {:?}", err); - return Ok(()); - } - }; - drop(repository_backend); - - let mut user_backend = connection_state.user_backend.lock().await; - let user_exists = user_backend.exists(&request.user).await; - - if repositories.is_empty() && !matches!(user_exists, Ok(true)) { - return Err(UserError::InvalidUser(request.user)); - } - - let response: UserRepositoriesResponse = UserRepositoriesResponse { repositories }; - - connection_state.send(response).await?; - - Ok(()) -} - -async fn user_settings( - Message(request): Message, - State(connection_state): State, - AuthenticatedUser(requesting_user): AuthenticatedUser, -) -> Result<(), UserError> { - if request.user != requesting_user { - return Err(UserError::InvalidUser(request.user)); - } - - let mut settings_backend = connection_state.settings_backend.lock().await; - let mut settings = settings_backend.user_get(&requesting_user).await?; - drop(settings_backend); - - let response = UserSettingsResponse { - settings: settings.drain(..).collect(), - }; - - connection_state.send(response).await?; - - Ok(()) -} - -async fn write_user_settings( - Message(request): Message, - State(connection_state): State, - AuthenticatedUser(requesting_user): AuthenticatedUser, -) -> Result<(), UserError> { - if request.user != requesting_user { - return Err(UserError::InvalidUser(request.user)); - } - - let mut settings_backend = connection_state.settings_backend.lock().await; - settings_backend - .user_write(&request.user, &request.settings) - .await?; - drop(settings_backend); - - let response = UserWriteSettingsResponse {}; - - connection_state.send(response).await?; - - Ok(()) -} - -#[derive(Debug, thiserror::Error)] -pub enum UserError { - #[error("invalid user {0}")] - InvalidUser(User), - #[error("{0}")] - Other(#[from] Error), -} diff --git a/giterated-models/src/repository/values.rs b/giterated-models/src/repository/values.rs index ab5e0d7..ac6e9f2 100644 --- a/giterated-models/src/repository/values.rs +++ b/giterated-models/src/repository/values.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use serde::{Deserialize, Serialize}; use crate::{settings::Setting, value::GiteratedObjectValue}; @@ -19,6 +21,12 @@ use super::{Repository, RepositoryVisibility}; #[derive(Debug, Hash, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Description(pub String); +impl Display for Description { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.0) + } +} + impl GiteratedObjectValue for Description { type Object = Repository;