From 34a7fd36338c6a0efc918f7a2e7777ae20987a94 Mon Sep 17 00:00:00 2001 From: khorshuheng Date: Tue, 15 Oct 2024 14:13:47 +0800 Subject: [PATCH 1/2] feat: additional access control config --- ...f94f105cdb23a59fefb846afe8105d91d129.json} | 4 +- libs/database-entity/src/dto.rs | 1 + libs/database/src/access_request.rs | 1 + libs/database/src/pg_row.rs | 2 + src/api/access_request.rs | 1 + src/api/workspace.rs | 152 +++++++++++++++--- src/application.rs | 39 ++--- src/biz/access_request/ops.rs | 21 ++- src/biz/workspace/ops.rs | 28 +--- src/config/config.rs | 16 ++ tests/workspace/workspace_settings.rs | 24 ++- 11 files changed, 196 insertions(+), 93 deletions(-) rename .sqlx/{query-0c3ae560880e82218d13c5992540386ea1566e45e31acd5fb51886aabcd98479.json => query-67b381fdcd20f8cfe782d939e56bf94f105cdb23a59fefb846afe8105d91d129.json} (70%) diff --git a/.sqlx/query-0c3ae560880e82218d13c5992540386ea1566e45e31acd5fb51886aabcd98479.json b/.sqlx/query-67b381fdcd20f8cfe782d939e56bf94f105cdb23a59fefb846afe8105d91d129.json similarity index 70% rename from .sqlx/query-0c3ae560880e82218d13c5992540386ea1566e45e31acd5fb51886aabcd98479.json rename to .sqlx/query-67b381fdcd20f8cfe782d939e56bf94f105cdb23a59fefb846afe8105d91d129.json index bfc48c6b2..6d785f251 100644 --- a/.sqlx/query-0c3ae560880e82218d13c5992540386ea1566e45e31acd5fb51886aabcd98479.json +++ b/.sqlx/query-67b381fdcd20f8cfe782d939e56bf94f105cdb23a59fefb846afe8105d91d129.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n WITH request_id_workspace_member_count AS (\n SELECT\n request_id,\n COUNT(*) AS member_count\n FROM af_access_request\n JOIN af_workspace_member USING (workspace_id)\n WHERE request_id = $1\n GROUP BY request_id\n )\n SELECT\n request_id,\n view_id,\n (\n workspace_id,\n af_workspace.database_storage_id,\n af_workspace.owner_uid,\n owner_profile.name,\n owner_profile.email,\n af_workspace.created_at,\n af_workspace.workspace_type,\n af_workspace.deleted_at,\n af_workspace.workspace_name,\n af_workspace.icon,\n request_id_workspace_member_count.member_count\n ) AS \"workspace!: AFWorkspaceWithMemberCountRow\",\n (\n af_user.uuid,\n af_user.name,\n af_user.email,\n af_user.metadata ->> 'icon_url'\n ) AS \"requester!: AFAccessRequesterColumn\",\n status AS \"status: AFAccessRequestStatusColumn\",\n af_access_request.created_at AS created_at\n FROM af_access_request\n JOIN af_user USING (uid)\n JOIN af_workspace USING (workspace_id)\n JOIN af_user AS owner_profile ON af_workspace.owner_uid = owner_profile.uid\n JOIN request_id_workspace_member_count USING (request_id)\n WHERE request_id = $1\n ", + "query": "\n WITH request_id_workspace_member_count AS (\n SELECT\n request_id,\n COUNT(*) AS member_count\n FROM af_access_request\n JOIN af_workspace_member USING (workspace_id)\n WHERE request_id = $1\n GROUP BY request_id\n )\n SELECT\n request_id,\n view_id,\n (\n workspace_id,\n af_workspace.database_storage_id,\n af_workspace.owner_uid,\n owner_profile.name,\n owner_profile.email,\n af_workspace.created_at,\n af_workspace.workspace_type,\n af_workspace.deleted_at,\n af_workspace.workspace_name,\n af_workspace.icon,\n request_id_workspace_member_count.member_count\n ) AS \"workspace!: AFWorkspaceWithMemberCountRow\",\n (\n af_user.uid,\n af_user.uuid,\n af_user.name,\n af_user.email,\n af_user.metadata ->> 'icon_url'\n ) AS \"requester!: AFAccessRequesterColumn\",\n status AS \"status: AFAccessRequestStatusColumn\",\n af_access_request.created_at AS created_at\n FROM af_access_request\n JOIN af_user USING (uid)\n JOIN af_workspace USING (workspace_id)\n JOIN af_user AS owner_profile ON af_workspace.owner_uid = owner_profile.uid\n JOIN request_id_workspace_member_count USING (request_id)\n WHERE request_id = $1\n ", "describe": { "columns": [ { @@ -48,5 +48,5 @@ false ] }, - "hash": "0c3ae560880e82218d13c5992540386ea1566e45e31acd5fb51886aabcd98479" + "hash": "67b381fdcd20f8cfe782d939e56bf94f105cdb23a59fefb846afe8105d91d129" } diff --git a/libs/database-entity/src/dto.rs b/libs/database-entity/src/dto.rs index 9d7fd4ab3..762677732 100644 --- a/libs/database-entity/src/dto.rs +++ b/libs/database-entity/src/dto.rs @@ -1397,6 +1397,7 @@ pub struct AccessRequestWithViewId { #[derive(Serialize, Deserialize, Debug)] pub struct AccessRequesterInfo { + pub uid: i64, pub uuid: Uuid, pub email: String, pub name: String, diff --git a/libs/database/src/access_request.rs b/libs/database/src/access_request.rs index 9b77a7093..27667a6b6 100644 --- a/libs/database/src/access_request.rs +++ b/libs/database/src/access_request.rs @@ -80,6 +80,7 @@ pub async fn select_access_request_by_request_id<'a, E: Executor<'a, Database = request_id_workspace_member_count.member_count ) AS "workspace!: AFWorkspaceWithMemberCountRow", ( + af_user.uid, af_user.uuid, af_user.name, af_user.email, diff --git a/libs/database/src/pg_row.rs b/libs/database/src/pg_row.rs index 72790a617..d77ef52a8 100644 --- a/libs/database/src/pg_row.rs +++ b/libs/database/src/pg_row.rs @@ -581,6 +581,7 @@ impl From for AccessRequestStatus { #[derive(sqlx::Type, Serialize, Debug)] pub struct AFAccessRequesterColumn { + pub uid: i64, pub uuid: Uuid, pub name: String, pub email: String, @@ -590,6 +591,7 @@ pub struct AFAccessRequesterColumn { impl From for AccessRequesterInfo { fn from(value: AFAccessRequesterColumn) -> Self { Self { + uid: value.uid, uuid: value.uuid, name: value.name, email: value.email, diff --git a/src/api/access_request.rs b/src/api/access_request.rs index e235f74a0..ec0fa2a90 100644 --- a/src/api/access_request.rs +++ b/src/api/access_request.rs @@ -100,6 +100,7 @@ async fn post_approve_access_request_handler( )))?; approve_or_reject_access_request( &state.pg_pool, + state.workspace_access_control.clone(), state.mailer.clone(), &appflowy_web_url, access_request_id, diff --git a/src/api/workspace.rs b/src/api/workspace.rs index f51bafea9..0a82efbf2 100644 --- a/src/api/workspace.rs +++ b/src/api/workspace.rs @@ -1,3 +1,4 @@ +use access_control::act::Action; use actix_web::web::{Bytes, Payload}; use actix_web::web::{Data, Json, PayloadConfig}; use actix_web::{web, Scope}; @@ -262,11 +263,24 @@ async fn patch_workspace_handler( } async fn delete_workspace_handler( - _user_id: UserUuid, + user_uuid: UserUuid, workspace_id: web::Path, state: Data, ) -> Result>> { - // TODO: add permission for workspace deletion + let uid = state.user_cache.get_user_uid(&user_uuid).await?; + let has_access = state + .workspace_access_control + .enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner) + .await?; + if !has_access { + return Err( + AppError::NotEnoughPermissions { + user: user_uuid.to_string(), + action: "delete workspace".to_string(), + } + .into(), + ); + } workspace::ops::delete_workspace_for_user( state.pg_pool.clone(), *workspace_id, @@ -299,6 +313,21 @@ async fn post_workspace_invite_handler( payload: Json>, state: Data, ) -> Result> { + let uid = state.user_cache.get_user_uid(&user_uuid).await?; + let has_access = state + .workspace_access_control + .enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner) + .await?; + if !has_access { + return Err( + AppError::NotEnoughPermissions { + user: user_uuid.to_string(), + action: "invite workspace member".to_string(), + } + .into(), + ); + } + let invited_members = payload.into_inner(); workspace::ops::invite_workspace_members( &state.mailer, @@ -367,13 +396,20 @@ async fn get_workspace_settings_handler( workspace_id: web::Path, ) -> Result> { let uid = state.user_cache.get_user_uid(&user_uuid).await?; - let settings = workspace::ops::get_workspace_settings( - &state.pg_pool, - state.workspace_access_control.clone(), - &workspace_id, - &uid, - ) - .await?; + let has_access = state + .workspace_access_control + .enforce_action(&uid, &workspace_id.to_string(), Action::Read) + .await?; + if !has_access { + return Err( + AppError::NotEnoughPermissions { + user: user_uuid.to_string(), + action: "read workspace setting".to_string(), + } + .into(), + ); + } + let settings = workspace::ops::get_workspace_settings(&state.pg_pool, &workspace_id).await?; Ok(AppResponse::Ok().with_data(settings).into()) } @@ -387,23 +423,44 @@ async fn post_workspace_settings_handler( let data = data.into_inner(); trace!("workspace settings: {:?}", data); let uid = state.user_cache.get_user_uid(&user_uuid).await?; - let settings = workspace::ops::update_workspace_settings( - &state.pg_pool, - state.workspace_access_control.clone(), - &workspace_id, - &uid, - data, - ) - .await?; + let has_access = state + .workspace_access_control + .enforce_action(&uid, &workspace_id.to_string(), Action::Write) + .await?; + if !has_access { + return Err( + AppError::NotEnoughPermissions { + user: user_uuid.to_string(), + action: "update workspace setting".to_string(), + } + .into(), + ); + } + let settings = + workspace::ops::update_workspace_settings(&state.pg_pool, &workspace_id, data).await?; Ok(AppResponse::Ok().with_data(settings).into()) } #[instrument(skip_all, err)] async fn get_workspace_members_handler( - _user_uuid: UserUuid, + user_uuid: UserUuid, state: Data, workspace_id: web::Path, ) -> Result>> { + let uid = state.user_cache.get_user_uid(&user_uuid).await?; + let has_access = state + .workspace_access_control + .enforce_action(&uid, &workspace_id.to_string(), Action::Read) + .await?; + if !has_access { + return Err( + AppError::NotEnoughPermissions { + user: user_uuid.to_string(), + action: "get workspace members".to_string(), + } + .into(), + ); + } let members = workspace::ops::get_workspace_members(&state.pg_pool, &workspace_id) .await? .into_iter() @@ -420,11 +477,26 @@ async fn get_workspace_members_handler( #[instrument(skip_all, err)] async fn remove_workspace_member_handler( - _user_uuid: UserUuid, + user_uuid: UserUuid, payload: Json, state: Data, workspace_id: web::Path, ) -> Result> { + let uid = state.user_cache.get_user_uid(&user_uuid).await?; + let has_access = state + .workspace_access_control + .enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner) + .await?; + if !has_access { + return Err( + AppError::NotEnoughPermissions { + user: user_uuid.to_string(), + action: "remove workspace member".to_string(), + } + .into(), + ); + } + let member_emails = payload .into_inner() .0 @@ -444,12 +516,28 @@ async fn remove_workspace_member_handler( #[instrument(skip_all, err)] async fn get_workspace_member_handler( + user_uuid: UserUuid, state: Data, path: web::Path<(Uuid, i64)>, ) -> Result> { - let (workspace_id, user_id) = path.into_inner(); + let (workspace_id, user_uuid_to_retrieved) = path.into_inner(); + let uid = state.user_cache.get_user_uid(&user_uuid).await?; + let has_access = state + .workspace_access_control + .enforce_action(&uid, &workspace_id.to_string(), Action::Read) + .await?; + if !has_access { + return Err( + AppError::NotEnoughPermissions { + user: user_uuid.to_string(), + action: "get workspace member".to_string(), + } + .into(), + ); + } let member_row = - workspace::ops::get_workspace_member(&user_id, &state.pg_pool, &workspace_id).await?; + workspace::ops::get_workspace_member(&user_uuid_to_retrieved, &state.pg_pool, &workspace_id) + .await?; let member = AFWorkspaceMember { name: member_row.name, email: member_row.email, @@ -490,21 +578,35 @@ async fn leave_workspace_handler( #[instrument(level = "debug", skip_all, err)] async fn update_workspace_member_handler( + user_uuid: UserUuid, payload: Json, state: Data, workspace_id: web::Path, ) -> Result> { - // TODO: only owner is allowed to update member role - let workspace_id = workspace_id.into_inner(); + let uid = state.user_cache.get_user_uid(&user_uuid).await?; + let has_access = state + .workspace_access_control + .enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner) + .await?; + if !has_access { + return Err( + AppError::NotEnoughPermissions { + user: user_uuid.to_string(), + action: "update workspace member".to_string(), + } + .into(), + ); + } + let changeset = payload.into_inner(); if changeset.role.is_some() { - let uid = select_uid_from_email(&state.pg_pool, &changeset.email) + let changeset_uid = select_uid_from_email(&state.pg_pool, &changeset.email) .await .map_err(AppResponseError::from)?; workspace::ops::update_workspace_member( - &uid, + &changeset_uid, &state.pg_pool, &workspace_id, &changeset, diff --git a/src/application.rs b/src/application.rs index 0666a515f..7c9494d1c 100644 --- a/src/application.rs +++ b/src/application.rs @@ -165,8 +165,10 @@ pub async fn run_actix_server( SessionMiddleware::builder(redis_store.clone(), key.clone()) .build(), ) - // .wrap(DecryptPayloadMiddleware) - .wrap(Condition::new(config.access_control.is_enabled, access_control.clone())) + .wrap(Condition::new( + config.access_control.is_enabled && config.access_control.enable_middleware, + access_control.clone()) + ) .wrap(RequestIdMiddleware) .service(server_info_scope()) .service(user_scope()) @@ -270,7 +272,6 @@ pub async fn init_state(config: &Config, rt_cmd_tx: CLCommandSender) -> Result Result = if config.access_control.is_enabled { - Arc::new(CollabAccessControlImpl::new(access_control.clone())) - } else { - Arc::new(NoOpsCollabAccessControlImpl::new()) - }; + let collab_access_control: Arc = + if config.access_control.is_enabled && config.access_control.enable_collab_access_control { + Arc::new(CollabAccessControlImpl::new(access_control.clone())) + } else { + Arc::new(NoOpsCollabAccessControlImpl::new()) + }; let workspace_access_control: Arc = - if config.access_control.is_enabled { + if config.access_control.is_enabled && config.access_control.enable_workspace_access_control { Arc::new(WorkspaceAccessControlImpl::new(access_control.clone())) } else { Arc::new(NoOpsWorkspaceAccessControlImpl::new()) }; - let realtime_access_control: Arc = if config.access_control.is_enabled - { - Arc::new(RealtimeCollabAccessControlImpl::new(access_control)) - } else { - Arc::new(NoOpsRealtimeCollabAccessControlImpl::new()) - }; + let realtime_access_control: Arc = + if config.access_control.is_enabled && config.access_control.enable_realtime_access_control { + Arc::new(RealtimeCollabAccessControlImpl::new(access_control)) + } else { + Arc::new(NoOpsRealtimeCollabAccessControlImpl::new()) + }; let collab_cache = CollabCache::new(redis_conn_manager.clone(), pg_pool.clone()); let collab_storage_access_control = CollabStorageAccessControlImpl { diff --git a/src/biz/access_request/ops.rs b/src/biz/access_request/ops.rs index 52f9774ca..6e8f7dfc6 100644 --- a/src/biz/access_request/ops.rs +++ b/src/biz/access_request/ops.rs @@ -8,6 +8,7 @@ use crate::{ }, mailer::{WorkspaceAccessRequestApprovedMailerParam, WorkspaceAccessRequestMailerParam}, }; +use access_control::workspace::WorkspaceAccessControl; use anyhow::Context; use app_error::AppError; use appflowy_collaborate::collab::storage::CollabAccessControlStorage; @@ -116,8 +117,10 @@ pub async fn get_access_request( Ok(access_request) } +#[allow(clippy::too_many_arguments)] pub async fn approve_or_reject_access_request( pg_pool: &PgPool, + workspace_access_control: Arc, mailer: AFCloudMailer, appflowy_web_url: &str, request_id: Uuid, @@ -126,7 +129,14 @@ pub async fn approve_or_reject_access_request( is_approved: bool, ) -> Result<(), AppError> { let access_request = select_access_request_by_request_id(pg_pool, request_id).await?; - if access_request.workspace.owner_uid != uid { + let has_access = workspace_access_control + .enforce_role( + &uid, + &access_request.workspace.workspace_id.to_string(), + AFRole::Owner, + ) + .await?; + if !has_access { return Err(AppError::NotEnoughPermissions { user: user_uuid.to_string(), action: "approve access request".to_string(), @@ -140,9 +150,16 @@ pub async fn approve_or_reject_access_request( &mut txn, &access_request.workspace.workspace_id, &access_request.requester.email, - role, + role.clone(), ) .await?; + workspace_access_control + .insert_role( + &access_request.requester.uid, + &access_request.workspace.workspace_id, + role.clone(), + ) + .await?; let cloned_mailer = mailer.clone(); let launch_workspace_url = format!( "{}/app/{}", diff --git a/src/biz/workspace/ops.rs b/src/biz/workspace/ops.rs index 449659448..7fa2c86ad 100644 --- a/src/biz/workspace/ops.rs +++ b/src/biz/workspace/ops.rs @@ -13,7 +13,7 @@ use tracing::instrument; use uuid::Uuid; use access_control::workspace::WorkspaceAccessControl; -use app_error::{AppError, ErrorCode}; +use app_error::AppError; use appflowy_collaborate::collab::storage::CollabAccessControlStorage; use database::collab::upsert_collab_member_with_txn; use database::file::s3_client_impl::S3BucketStorage; @@ -611,43 +611,17 @@ pub async fn get_workspace_document_total_bytes( pub async fn get_workspace_settings( pg_pool: &PgPool, - workspace_access_control: Arc, workspace_id: &Uuid, - owner_uid: &i64, ) -> Result { - let has_access = workspace_access_control - .enforce_role(owner_uid, &workspace_id.to_string(), AFRole::Owner) - .await?; - - if !has_access { - return Err(AppResponseError::new( - ErrorCode::UserUnAuthorized, - "Only workspace owner can access workspace settings", - )); - } - let settings = select_workspace_settings(pg_pool, workspace_id).await?; Ok(settings.unwrap_or_default()) } pub async fn update_workspace_settings( pg_pool: &PgPool, - workspace_access_control: Arc, workspace_id: &Uuid, - owner_uid: &i64, change: AFWorkspaceSettingsChange, ) -> Result { - let has_access = workspace_access_control - .enforce_role(owner_uid, &workspace_id.to_string(), AFRole::Owner) - .await?; - - if !has_access { - return Err(AppResponseError::new( - ErrorCode::UserUnAuthorized, - "Only workspace owner can edit workspace settings", - )); - } - let mut tx = pg_pool.begin().await?; let mut setting = select_workspace_settings(tx.deref_mut(), workspace_id) .await? diff --git a/src/config/config.rs b/src/config/config.rs index 7832a9008..575370ebb 100644 --- a/src/config/config.rs +++ b/src/config/config.rs @@ -33,6 +33,10 @@ pub struct Config { pub struct AccessControlSetting { pub is_enabled: bool, + pub enable_middleware: bool, + pub enable_workspace_access_control: bool, + pub enable_collab_access_control: bool, + pub enable_realtime_access_control: bool, } #[derive(serde::Deserialize, Clone, Debug)] @@ -176,6 +180,18 @@ pub fn get_configuration() -> Result { is_enabled: get_env_var("APPFLOWY_ACCESS_CONTROL", "false") .parse() .context("fail to get APPFLOWY_ACCESS_CONTROL")?, + enable_middleware: get_env_var("APPFLOWY_ACCESS_CONTROL_MIDDLEWARE", "true") + .parse() + .context("fail to get APPFLOWY_ACCESS_CONTROL_MIDDLEWARE")?, + enable_workspace_access_control: get_env_var("APPFLOWY_ACCESS_CONTROL_WORKSPACE", "true") + .parse() + .context("fail to get APPFLOWY_ACCESS_CONTROL_WORKSPACE")?, + enable_collab_access_control: get_env_var("APPFLOWY_ACCESS_CONTROL_COLLAB", "true") + .parse() + .context("fail to get APPFLOWY_ACCESS_CONTROL_COLLAB")?, + enable_realtime_access_control: get_env_var("APPFLOWY_ACCESS_CONTROL_REALTIME", "true") + .parse() + .context("fail to get APPFLOWY_ACCESS_CONTROL_REALTIME")?, }, db_settings: DatabaseSetting { pg_conn_opts: PgConnectOptions::from_str(&get_env_var( diff --git a/tests/workspace/workspace_settings.rs b/tests/workspace/workspace_settings.rs index 47e6ef198..d97a5834d 100644 --- a/tests/workspace/workspace_settings.rs +++ b/tests/workspace/workspace_settings.rs @@ -1,4 +1,3 @@ -use app_error::ErrorCode; use client_api::Client; use client_api_test::generate_unique_registered_user_client; use database_entity::dto::{AFRole, AFWorkspaceInvitationStatus, AFWorkspaceSettingsChange}; @@ -31,6 +30,9 @@ async fn get_and_set_workspace_by_owner() { #[tokio::test] async fn get_and_set_workspace_by_non_owner() { + // TODO: currently, workspace settings contains only AI preference, which is + // better suited as a user setting. Meanwhile, we can permit workspace members + // to view the settings. let (alice_client, _alice) = generate_unique_registered_user_client().await; let workspaces = alice_client.get_workspaces().await.unwrap(); let alice_workspace_id = workspaces.first().unwrap().workspace_id; @@ -39,26 +41,18 @@ async fn get_and_set_workspace_by_non_owner() { invite_user_to_workspace(&alice_workspace_id, &alice_client, &bob_client, &bob.email).await; - let resp = bob_client + bob_client .get_workspace_settings(&alice_workspace_id.to_string()) - .await; - assert!( - resp.is_err(), - "non-owner should not have access to workspace settings" - ); - assert_eq!(resp.err().unwrap().code, ErrorCode::UserUnAuthorized); + .await + .unwrap(); - let resp = bob_client + bob_client .update_workspace_settings( &alice_workspace_id.to_string(), &AFWorkspaceSettingsChange::new().disable_search_indexing(true), ) - .await; - assert!( - resp.is_err(), - "non-owner should not be able to edit workspace settings" - ); - assert_eq!(resp.err().unwrap().code, ErrorCode::UserUnAuthorized); + .await + .unwrap(); } async fn invite_user_to_workspace( From 383629ab1c0e2dacf20e1bce3caab10c3add04c3 Mon Sep 17 00:00:00 2001 From: khorshuheng Date: Wed, 16 Oct 2024 15:10:31 +0800 Subject: [PATCH 2/2] chore: simplify not enough permission error --- libs/app-error/src/lib.rs | 4 +- libs/database/src/workspace.rs | 5 +- .../src/collab/storage.rs | 20 ++---- src/api/access_request.rs | 2 - src/api/workspace.rs | 64 +++---------------- src/biz/access_request/ops.rs | 12 +--- src/biz/collab/access_control.rs | 10 +-- src/biz/workspace/access_control.rs | 10 +-- 8 files changed, 19 insertions(+), 108 deletions(-) diff --git a/libs/app-error/src/lib.rs b/libs/app-error/src/lib.rs index 5b6825557..ceba24c9a 100644 --- a/libs/app-error/src/lib.rs +++ b/libs/app-error/src/lib.rs @@ -64,8 +64,8 @@ pub enum AppError { #[error("Not Logged In:{0}")] NotLoggedIn(String), - #[error("{user}: do not have permissions to {action}")] - NotEnoughPermissions { user: String, action: String }, + #[error("User does not have permissions to execute this action")] + NotEnoughPermissions, #[error("s3 response error:{0}")] S3ResponseError(String), diff --git a/libs/database/src/workspace.rs b/libs/database/src/workspace.rs index 56a31bc5a..ba120e064 100644 --- a/libs/database/src/workspace.rs +++ b/libs/database/src/workspace.rs @@ -517,10 +517,7 @@ pub async fn delete_workspace_members( .unwrap_or(false); if is_owner { - return Err(AppError::NotEnoughPermissions { - user: member_email.to_string(), - action: format!("delete member from workspace {}", workspace_id), - }); + return Err(AppError::NotEnoughPermissions); } sqlx::query!( diff --git a/services/appflowy-collaborate/src/collab/storage.rs b/services/appflowy-collaborate/src/collab/storage.rs index 43660945a..39f546c7f 100644 --- a/services/appflowy-collaborate/src/collab/storage.rs +++ b/services/appflowy-collaborate/src/collab/storage.rs @@ -92,10 +92,7 @@ where .await?; if !can_write_workspace { - return Err(AppError::NotEnoughPermissions { - user: uid.to_string(), - action: format!("write workspace:{}", workspace_id), - }); + return Err(AppError::NotEnoughPermissions); } Ok(()) } @@ -113,10 +110,7 @@ where .await?; if !can_write { - return Err(AppError::NotEnoughPermissions { - user: uid.to_string(), - action: format!("update collab:{}", object_id), - }); + return Err(AppError::NotEnoughPermissions); } Ok(()) } @@ -375,10 +369,7 @@ where .await?; if !can_read { - return Err(AppError::NotEnoughPermissions { - user: uid.to_string(), - action: format!("read collab:{}", params.object_id), - }); + return Err(AppError::NotEnoughPermissions); } }, GetCollabOrigin::Server => {}, @@ -470,10 +461,7 @@ where .enforce_delete(workspace_id, uid, object_id) .await? { - return Err(AppError::NotEnoughPermissions { - user: uid.to_string(), - action: format!("delete collab:{}", object_id), - }); + return Err(AppError::NotEnoughPermissions); } self.cache.delete_collab(object_id).await?; Ok(()) diff --git a/src/api/access_request.rs b/src/api/access_request.rs index ec0fa2a90..2723afaa0 100644 --- a/src/api/access_request.rs +++ b/src/api/access_request.rs @@ -42,7 +42,6 @@ async fn get_access_request_handler( &state.pg_pool, state.collab_access_control_storage.clone(), access_request_id, - *uuid, uid, ) .await?; @@ -105,7 +104,6 @@ async fn post_approve_access_request_handler( &appflowy_web_url, access_request_id, uid, - *uuid, is_approved, ) .await?; diff --git a/src/api/workspace.rs b/src/api/workspace.rs index 0a82efbf2..ce943fcbd 100644 --- a/src/api/workspace.rs +++ b/src/api/workspace.rs @@ -273,13 +273,7 @@ async fn delete_workspace_handler( .enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner) .await?; if !has_access { - return Err( - AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "delete workspace".to_string(), - } - .into(), - ); + return Err(AppError::NotEnoughPermissions.into()); } workspace::ops::delete_workspace_for_user( state.pg_pool.clone(), @@ -319,13 +313,7 @@ async fn post_workspace_invite_handler( .enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner) .await?; if !has_access { - return Err( - AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "invite workspace member".to_string(), - } - .into(), - ); + return Err(AppError::NotEnoughPermissions.into()); } let invited_members = payload.into_inner(); @@ -401,13 +389,7 @@ async fn get_workspace_settings_handler( .enforce_action(&uid, &workspace_id.to_string(), Action::Read) .await?; if !has_access { - return Err( - AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "read workspace setting".to_string(), - } - .into(), - ); + return Err(AppError::NotEnoughPermissions.into()); } let settings = workspace::ops::get_workspace_settings(&state.pg_pool, &workspace_id).await?; Ok(AppResponse::Ok().with_data(settings).into()) @@ -428,13 +410,7 @@ async fn post_workspace_settings_handler( .enforce_action(&uid, &workspace_id.to_string(), Action::Write) .await?; if !has_access { - return Err( - AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "update workspace setting".to_string(), - } - .into(), - ); + return Err(AppError::NotEnoughPermissions.into()); } let settings = workspace::ops::update_workspace_settings(&state.pg_pool, &workspace_id, data).await?; @@ -453,13 +429,7 @@ async fn get_workspace_members_handler( .enforce_action(&uid, &workspace_id.to_string(), Action::Read) .await?; if !has_access { - return Err( - AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "get workspace members".to_string(), - } - .into(), - ); + return Err(AppError::NotEnoughPermissions.into()); } let members = workspace::ops::get_workspace_members(&state.pg_pool, &workspace_id) .await? @@ -488,13 +458,7 @@ async fn remove_workspace_member_handler( .enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner) .await?; if !has_access { - return Err( - AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "remove workspace member".to_string(), - } - .into(), - ); + return Err(AppError::NotEnoughPermissions.into()); } let member_emails = payload @@ -527,13 +491,7 @@ async fn get_workspace_member_handler( .enforce_action(&uid, &workspace_id.to_string(), Action::Read) .await?; if !has_access { - return Err( - AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "get workspace member".to_string(), - } - .into(), - ); + return Err(AppError::NotEnoughPermissions.into()); } let member_row = workspace::ops::get_workspace_member(&user_uuid_to_retrieved, &state.pg_pool, &workspace_id) @@ -590,13 +548,7 @@ async fn update_workspace_member_handler( .enforce_role(&uid, &workspace_id.to_string(), AFRole::Owner) .await?; if !has_access { - return Err( - AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "update workspace member".to_string(), - } - .into(), - ); + return Err(AppError::NotEnoughPermissions.into()); } let changeset = payload.into_inner(); diff --git a/src/biz/access_request/ops.rs b/src/biz/access_request/ops.rs index 6e8f7dfc6..4d48f13e9 100644 --- a/src/biz/access_request/ops.rs +++ b/src/biz/access_request/ops.rs @@ -74,16 +74,12 @@ pub async fn get_access_request( pg_pool: &PgPool, collab_storage: Arc, access_request_id: Uuid, - user_uuid: Uuid, user_uid: i64, ) -> Result { let access_request_with_view_id = select_access_request_by_request_id(pg_pool, access_request_id).await?; if access_request_with_view_id.workspace.owner_uid != user_uid { - return Err(AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "get access request".to_string(), - }); + return Err(AppError::NotEnoughPermissions); } let folder = get_latest_collab_folder( collab_storage, @@ -125,7 +121,6 @@ pub async fn approve_or_reject_access_request( appflowy_web_url: &str, request_id: Uuid, uid: i64, - user_uuid: Uuid, is_approved: bool, ) -> Result<(), AppError> { let access_request = select_access_request_by_request_id(pg_pool, request_id).await?; @@ -137,10 +132,7 @@ pub async fn approve_or_reject_access_request( ) .await?; if !has_access { - return Err(AppError::NotEnoughPermissions { - user: user_uuid.to_string(), - action: "approve access request".to_string(), - }); + return Err(AppError::NotEnoughPermissions); } let mut txn = pg_pool.begin().await.context("approving request")?; diff --git a/src/biz/collab/access_control.rs b/src/biz/collab/access_control.rs index 7c8d3754e..a7a0650e2 100644 --- a/src/biz/collab/access_control.rs +++ b/src/biz/collab/access_control.rs @@ -119,15 +119,7 @@ impl MiddlewareAccessControl for CollabMiddlewareAccessControl { if result { Ok(()) } else { - Err(AppError::NotEnoughPermissions { - user: uid.to_string(), - action: format!( - "access collab:{} with url:{}, method:{}", - oid, - path.as_str(), - method - ), - }) + Err(AppError::NotEnoughPermissions) } } } diff --git a/src/biz/workspace/access_control.rs b/src/biz/workspace/access_control.rs index 6a3457760..88019c9fc 100644 --- a/src/biz/workspace/access_control.rs +++ b/src/biz/workspace/access_control.rs @@ -142,15 +142,7 @@ impl MiddlewareAccessControl for WorkspaceMiddlewareAccessControl { if result { Ok(()) } else { - Err(AppError::NotEnoughPermissions { - user: uid.to_string(), - action: format!( - "access workspace:{} with given url:{}, method: {}", - resource_id, - path.as_str(), - method, - ), - }) + Err(AppError::NotEnoughPermissions) } } }