diff --git a/giterated-daemon/src/backend/git.rs b/giterated-daemon/src/backend/git.rs index 6dc17cb..2f1fdcb 100644 --- a/giterated-daemon/src/backend/git.rs +++ b/giterated-daemon/src/backend/git.rs @@ -16,8 +16,10 @@ use giterated_models::repository::{ use giterated_models::settings::{AnySetting, Setting}; use giterated_models::user::{User, UserParseError}; use giterated_models::value::{AnyValue, GiteratedObjectValue}; +use giterated_stack::AuthenticatedUser; use serde_json::Value; use sqlx::PgPool; +use std::ops::Deref; use std::{ path::{Path, PathBuf}, sync::Arc, @@ -47,7 +49,7 @@ impl GitRepository { pub async fn can_user_view_repository( &self, our_instance: &Instance, - user: Option<&User>, + user: &Option, settings: &Arc>, ) -> bool { info!( @@ -64,7 +66,7 @@ impl GitRepository { None => return false, }; - if *user == self.owner_user { + if *user.deref() == self.owner_user { // owner can always view return true; } @@ -99,7 +101,7 @@ impl GitRepository { access_list .0 .iter() - .find(|access_list_user| *access_list_user == user) + .find(|access_list_user| *access_list_user == user.deref()) .is_some() } else { false @@ -241,7 +243,7 @@ impl GitBackend { &self, owner: &User, name: &str, - requester: Option<&User>, + requester: &Option, ) -> Result { info!( "Checking permissions for user {:?} on {}/{}", @@ -261,7 +263,11 @@ impl GitBackend { if let Some(requester) = requester { if !repository - .can_user_view_repository(&self.instance, Some(requester), &self.settings_provider) + .can_user_view_repository( + &self.instance, + &Some(requester.clone()), + &self.settings_provider, + ) .await { return Err(GitBackendError::RepositoryNotFound { @@ -329,12 +335,18 @@ impl GitBackend { #[async_trait] impl RepositoryBackend for GitBackend { - async fn exists(&mut self, repository: &Repository) -> Result { - if let Ok(_repository) = self + async fn exists( + &mut self, + requester: &Option, + repository: &Repository, + ) -> Result { + if let Ok(repository) = self .find_by_owner_user_name(&repository.owner.clone(), &repository.name) .await { - Ok(true) + Ok(repository + .can_user_view_repository(&self.instance, requester, &self.settings_provider) + .await) } else { Ok(false) } @@ -342,7 +354,7 @@ impl RepositoryBackend for GitBackend { async fn create_repository( &mut self, - _user: &User, + _user: &AuthenticatedUser, request: &RepositoryCreateRequest, ) -> Result { // Check if repository already exists in the database @@ -491,7 +503,7 @@ impl RepositoryBackend for GitBackend { async fn repository_file_inspect( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryFileInspectRequest, ) -> Result, Error> { @@ -616,7 +628,7 @@ impl RepositoryBackend for GitBackend { async fn repository_file_from_id( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryFileFromIdRequest, ) -> Result { @@ -647,7 +659,7 @@ impl RepositoryBackend for GitBackend { async fn repository_file_from_path( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryFileFromPathRequest, ) -> Result { @@ -733,7 +745,7 @@ impl RepositoryBackend for GitBackend { async fn repository_diff( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryDiffRequest, ) -> Result { @@ -862,7 +874,7 @@ impl RepositoryBackend for GitBackend { async fn repository_diff_patch( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryDiffPatchRequest, ) -> Result { @@ -917,7 +929,7 @@ impl RepositoryBackend for GitBackend { async fn repository_commit_before( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryCommitBeforeRequest, ) -> Result { @@ -967,7 +979,7 @@ impl RepositoryBackend for GitBackend { impl IssuesBackend for GitBackend { fn issues_count( &mut self, - _requester: Option<&User>, + _requester: &Option, _request: &RepositoryIssuesCountRequest, ) -> Result { todo!() @@ -975,7 +987,7 @@ impl IssuesBackend for GitBackend { fn issue_labels( &mut self, - _requester: Option<&User>, + _requester: &Option, _request: &RepositoryIssueLabelsRequest, ) -> Result, Error> { todo!() @@ -983,7 +995,7 @@ impl IssuesBackend for GitBackend { fn issues( &mut self, - _requester: Option<&User>, + _requester: &Option, _request: &RepositoryIssuesRequest, ) -> Result, Error> { todo!() diff --git a/giterated-daemon/src/backend/mod.rs b/giterated-daemon/src/backend/mod.rs index 4236838..092cf30 100644 --- a/giterated-daemon/src/backend/mod.rs +++ b/giterated-daemon/src/backend/mod.rs @@ -6,6 +6,7 @@ pub mod user; use anyhow::Error; use async_trait::async_trait; +use giterated_stack::AuthenticatedUser; use serde_json::Value; use crate::backend::git::GitBackendError; @@ -30,42 +31,42 @@ use giterated_models::value::AnyValue; pub trait RepositoryBackend { async fn create_repository( &mut self, - user: &User, + user: &AuthenticatedUser, request: &RepositoryCreateRequest, ) -> Result; async fn repository_file_inspect( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryFileInspectRequest, ) -> Result, Error>; async fn repository_file_from_id( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryFileFromIdRequest, ) -> Result; async fn repository_file_from_path( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryFileFromPathRequest, ) -> Result; async fn repository_diff( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryDiffRequest, ) -> Result; async fn repository_diff_patch( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryDiffPatchRequest, ) -> Result; async fn repository_commit_before( &mut self, - requester: Option<&User>, + requester: &Option, repository: &Repository, request: &RepositoryCommitBeforeRequest, ) -> Result; @@ -81,23 +82,27 @@ pub trait RepositoryBackend { name: &str, setting: &Value, ) -> Result<(), Error>; - async fn exists(&mut self, repository: &Repository) -> Result; + async fn exists( + &mut self, + requester: &Option, + repository: &Repository, + ) -> Result; } pub trait IssuesBackend { fn issues_count( &mut self, - requester: Option<&User>, + requester: &Option, request: &RepositoryIssuesCountRequest, ) -> Result; fn issue_labels( &mut self, - requester: Option<&User>, + requester: &Option, request: &RepositoryIssueLabelsRequest, ) -> Result, Error>; fn issues( &mut self, - requester: Option<&User>, + requester: &Option, request: &RepositoryIssuesRequest, ) -> Result, Error>; } @@ -129,7 +134,7 @@ pub trait UserBackend: AuthBackend { async fn exists(&mut self, user: &User) -> Result; async fn repositories_for_user( &mut self, - requester: Option<&User>, + requester: &Option, user: &User, ) -> Result, Error>; } diff --git a/giterated-daemon/src/backend/user.rs b/giterated-daemon/src/backend/user.rs index c294e83..f9149a3 100644 --- a/giterated-daemon/src/backend/user.rs +++ b/giterated-daemon/src/backend/user.rs @@ -8,6 +8,7 @@ use giterated_models::repository::{Repository, RepositorySummary}; use giterated_models::settings::{AnySetting, Setting}; use giterated_models::user::{Bio, DisplayName, User, UserParseError}; use giterated_models::value::AnyValue; +use giterated_stack::AuthenticatedUser; use std::sync::Arc; use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, Key, KeyInit}; @@ -98,7 +99,7 @@ impl UserBackend for UserAuth { async fn repositories_for_user( &mut self, - _requester: Option<&User>, + _requester: &Option, user: &User, ) -> Result, Error> { let mut repositories = sqlx::query_as!( diff --git a/giterated-daemon/src/database_backend/handler.rs b/giterated-daemon/src/database_backend/handler.rs index a337f32..799341f 100644 --- a/giterated-daemon/src/database_backend/handler.rs +++ b/giterated-daemon/src/database_backend/handler.rs @@ -19,7 +19,7 @@ use giterated_models::{ user::{User, UserRepositoriesRequest}, value::{AnyValue, GetValue}, }; -use giterated_stack::{BackendWrapper, StackOperationState}; +use giterated_stack::{AuthenticatedUser, BackendWrapper, StackOperationState}; use super::DatabaseBackend; @@ -27,16 +27,31 @@ pub fn user_get_repositories( object: &User, _operation: UserRepositoriesRequest, state: DatabaseBackend, + operation_state: StackOperationState, + requester: Option, ) -> BoxFuture<'static, Result, OperationError>> { let object = object.clone(); async move { let mut user_backend = state.user_backend.lock().await; - let repositories = user_backend - .repositories_for_user(None, &object) + let repositories_response = user_backend + .repositories_for_user(&requester, &object) .await .map_err(|e| OperationError::Internal(e.to_string()))?; + let mut repositories = vec![]; + + for repository in repositories_response { + if operation_state + .giterated_backend + .get_object::(&repository.repository.to_string(), &operation_state) + .await + .is_ok() + { + repositories.push(repository); + } + } + Ok(repositories) } .boxed() @@ -105,6 +120,7 @@ pub fn repository_info( state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, + requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); @@ -117,7 +133,7 @@ pub fn repository_info( let mut repository_backend = state.repository_backend.lock().await; let tree = repository_backend .repository_file_inspect( - None, + &requester, object.object(), &RepositoryFileInspectRequest { extra_metadata: operation.extra_metadata, @@ -158,6 +174,7 @@ pub fn repository_file_from_id( state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, + requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); @@ -170,7 +187,7 @@ pub fn repository_file_from_id( let mut repository_backend = state.repository_backend.lock().await; let file = repository_backend .repository_file_from_id( - None, + &requester, object.object(), &RepositoryFileFromIdRequest(operation.0), ) @@ -189,6 +206,7 @@ pub fn repository_file_from_path( state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, + requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); @@ -201,7 +219,7 @@ pub fn repository_file_from_path( let mut repository_backend = state.repository_backend.lock().await; let file = repository_backend .repository_file_from_path( - None, + &requester, object.object(), &RepositoryFileFromPathRequest { rev: operation.rev, @@ -223,6 +241,7 @@ pub fn repository_diff( state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, + requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); @@ -234,7 +253,7 @@ pub fn repository_diff( let mut repository_backend = state.repository_backend.lock().await; let diff = repository_backend - .repository_diff(None, object.object(), &operation) + .repository_diff(&requester, object.object(), &operation) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); @@ -250,6 +269,7 @@ pub fn repository_diff_patch( state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, + requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); @@ -261,7 +281,7 @@ pub fn repository_diff_patch( let mut repository_backend = state.repository_backend.lock().await; let patch = repository_backend - .repository_diff_patch(None, object.object(), &operation) + .repository_diff_patch(&requester, object.object(), &operation) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); @@ -277,6 +297,7 @@ pub fn repository_commit_before( state: DatabaseBackend, operation_state: StackOperationState, backend: BackendWrapper, + requester: Option, ) -> BoxFuture<'static, Result>> { let object = object.clone(); @@ -288,7 +309,7 @@ pub fn repository_commit_before( let mut repository_backend = state.repository_backend.lock().await; let file = repository_backend - .repository_commit_before(None, object.object(), &operation) + .repository_commit_before(&requester, object.object(), &operation) .await .map_err(|err| OperationError::Internal(format!("{:?}", err)))?; drop(repository_backend); @@ -394,12 +415,13 @@ pub fn instance_create_repository_request( _object: &Instance, operation: RepositoryCreateRequest, state: DatabaseBackend, + requester: AuthenticatedUser, ) -> BoxFuture<'static, Result>> { async move { let mut backend = state.repository_backend.lock().await; backend - .create_repository(&operation.owner, &operation) + .create_repository(&requester, &operation) .await .map_err(|e| OperationError::Internal(e.to_string())) } diff --git a/giterated-daemon/src/database_backend/mod.rs b/giterated-daemon/src/database_backend/mod.rs index c2cea57..bd4ca54 100644 --- a/giterated-daemon/src/database_backend/mod.rs +++ b/giterated-daemon/src/database_backend/mod.rs @@ -131,7 +131,7 @@ mod test { use giterated_models::user::{DisplayName, User}; use giterated_models::value::{AnyValue, GiteratedObjectValue}; use giterated_stack::handler::GiteratedBackend; - use giterated_stack::StackOperationState; + use giterated_stack::{AuthenticatedUser, StackOperationState}; use serde_json::Value; use tokio::sync::Mutex; @@ -169,7 +169,7 @@ mod test { } async fn repositories_for_user( &mut self, - _requester: Option<&User>, + _requester: &Option, _user: &User, ) -> Result, Error> { todo!() @@ -200,14 +200,14 @@ mod test { impl RepositoryBackend for TestUserRepositoryBackend { async fn create_repository( &mut self, - _user: &User, + _user: &AuthenticatedUser, _request: &RepositoryCreateRequest, ) -> Result { todo!() } async fn repository_file_inspect( &mut self, - _requester: Option<&User>, + _requester: &Option, _repository: &Repository, _request: &RepositoryFileInspectRequest, ) -> Result, Error> { @@ -215,7 +215,7 @@ mod test { } async fn repository_file_from_id( &mut self, - _requester: Option<&User>, + _requester: &Option, _repository: &Repository, _request: &RepositoryFileFromIdRequest, ) -> Result { @@ -223,7 +223,7 @@ mod test { } async fn repository_file_from_path( &mut self, - _requester: Option<&User>, + _requester: &Option, _repository: &Repository, _request: &RepositoryFileFromPathRequest, ) -> Result { @@ -231,7 +231,7 @@ mod test { } async fn repository_diff( &mut self, - _requester: Option<&User>, + _requester: &Option, _repository: &Repository, _request: &RepositoryDiffRequest, ) -> Result { @@ -239,7 +239,7 @@ mod test { } async fn repository_diff_patch( &mut self, - _requester: Option<&User>, + _requester: &Option, _repository: &Repository, _request: &RepositoryDiffPatchRequest, ) -> Result { @@ -247,7 +247,7 @@ mod test { } async fn repository_commit_before( &mut self, - _requester: Option<&User>, + _requester: &Option, _repository: &Repository, _request: &RepositoryCommitBeforeRequest, ) -> Result { @@ -282,7 +282,11 @@ mod test { Ok(()) } - async fn exists(&mut self, repository: &Repository) -> Result { + async fn exists( + &mut self, + _requester: &Option, + repository: &Repository, + ) -> Result { // Ok(true) Ok(repository == &Repository::from_str( diff --git a/giterated-models/src/repository/settings.rs b/giterated-models/src/repository/settings.rs index fd3926a..98f12c6 100644 --- a/giterated-models/src/repository/settings.rs +++ b/giterated-models/src/repository/settings.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use crate::{settings::Setting, user::User}; -use super::{DefaultBranch, RepositoryVisibility}; +use super::DefaultBranch; impl Setting for DefaultBranch { fn name() -> &'static str { diff --git a/giterated-stack/src/lib.rs b/giterated-stack/src/lib.rs index 4cd833e..03b61fa 100644 --- a/giterated-stack/src/lib.rs +++ b/giterated-stack/src/lib.rs @@ -297,6 +297,57 @@ where } } +#[async_trait::async_trait] +impl GiteratedOperationHandler<(O1, O2, O3), O, D, S> for F +where + F: FnMut( + &O, + D, + S, + O1, + O2, + O3, + ) -> Pin< + Box>> + Send>, + > + Send + + Sync + + Clone, + O: GiteratedObject + Send + Sync, + D: GiteratedOperation + 'static, + >::Failure: Send, + S: Send + Sync + Clone + 'static, + O1: FromOperationState, + O2: FromOperationState, + O3: FromOperationState, +{ + fn operation_name(&self) -> &str { + D::operation_name() + } + + fn object_name(&self) -> &str { + O::object_name() + } + + async fn handle( + &self, + object: &O, + operation: D, + state: S, + operation_state: &StackOperationState, + ) -> Result> { + let o1 = O1::from_state(operation_state) + .await + .map_err(|e| OperationError::Internal(e.to_string()))?; + let o2 = O2::from_state(operation_state) + .await + .map_err(|e| OperationError::Internal(e.to_string()))?; + let o3 = O3::from_state(operation_state) + .await + .map_err(|e| OperationError::Internal(e.to_string()))?; + self.clone()(object, operation, state, o1, o2, o3).await + } +} + pub struct OperationWrapper { func: Box< dyn Fn( @@ -391,6 +442,43 @@ impl FromOperationState for StackOperationState { } } +#[async_trait::async_trait] +impl FromOperationState for AuthenticatedUser { + type Error = (); + + async fn from_state( + state: &StackOperationState, + ) -> Result> { + state + .user + .clone() + .ok_or_else(|| OperationError::Operation(())) + } +} + +#[async_trait::async_trait] +impl FromOperationState for AuthenticatedInstance { + type Error = (); + + async fn from_state( + state: &StackOperationState, + ) -> Result> { + state + .instance + .clone() + .ok_or_else(|| OperationError::Operation(())) + } +} + +#[async_trait::async_trait] +impl FromOperationState for Option { + type Error = (); + + async fn from_state(state: &StackOperationState) -> Result, OperationError<()>> { + Ok(T::from_state(state).await.ok()) + } +} + #[derive(Clone)] pub struct StackOperationState { pub giterated_backend: BackendWrapper,