From 7a0b33f7097a0465bff7a1b44d4d7cff870f344d Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Sat, 25 May 2024 22:35:56 +0200 Subject: [PATCH] add group support for Cipher::get_collections() join group infos assigned to a collection to check whether user has been given access to all collections via any group or they have access to a specific collection via any group membership --- src/api/core/ciphers.rs | 6 ++-- src/db/models/cipher.rs | 75 ++++++++++++++++++++++++++++------------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index 9a4456a4..036bb588 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -747,9 +747,9 @@ async fn post_collections_admin( err!("Cipher is not write accessible") } - let posted_collections: HashSet = data.collection_ids.iter().cloned().collect(); - let current_collections: HashSet = - cipher.get_collections(headers.user.uuid.clone(), &mut conn).await.iter().cloned().collect(); + let posted_collections = HashSet::::from_iter(data.collection_ids); + let current_collections = + HashSet::::from_iter(cipher.get_collections(headers.user.uuid.clone(), &mut conn).await); for collection in posted_collections.symmetric_difference(¤t_collections) { match Collection::find_by_uuid(collection, &mut conn).await { diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs index f765f470..03a1f20f 100644 --- a/src/db/models/cipher.rs +++ b/src/db/models/cipher.rs @@ -773,30 +773,59 @@ impl Cipher { } pub async fn get_collections(&self, user_id: String, conn: &mut DbConn) -> Vec { - db_run! {conn: { - ciphers_collections::table - .inner_join(collections::table.on( - collections::uuid.eq(ciphers_collections::collection_uuid) - )) - .inner_join(users_organizations::table.on( - users_organizations::org_uuid.eq(collections::org_uuid).and( - users_organizations::user_uuid.eq(user_id.clone()) + if CONFIG.org_groups_enabled() { + db_run! {conn: { + ciphers_collections::table + .inner_join(collections::table.on( + collections::uuid.eq(ciphers_collections::collection_uuid) + )) + .left_join(users_organizations::table.on( + users_organizations::org_uuid.eq(collections::org_uuid) + .and(users_organizations::user_uuid.eq(user_id.clone())) + )) + .left_join(users_collections::table.on( + users_collections::collection_uuid.eq(ciphers_collections::collection_uuid) + .and(users_collections::user_uuid.eq(user_id.clone())) + )) + .left_join(groups_users::table.on( + groups_users::users_organizations_uuid.eq(users_organizations::uuid) + )) + .left_join(groups::table.on(groups::uuid.eq(groups_users::groups_uuid))) + .left_join(collections_groups::table.on( + collections_groups::collections_uuid.eq(ciphers_collections::collection_uuid) + .and(collections_groups::groups_uuid.eq(groups::uuid)) + )) + .filter(ciphers_collections::cipher_uuid.eq(&self.uuid)) + .filter(users_organizations::access_all.eq(true) // User has access all + .or(users_collections::user_uuid.eq(user_id)) // User has access to collection + .or(groups::access_all.eq(true)) // Access via groups + .or(collections_groups::collections_uuid.is_not_null()) // Access via groups + ) + .select(ciphers_collections::collection_uuid) + .load::(conn).unwrap_or_default() + }} + } else { + db_run! {conn: { + ciphers_collections::table + .inner_join(collections::table.on( + collections::uuid.eq(ciphers_collections::collection_uuid) + )) + .inner_join(users_organizations::table.on( + users_organizations::org_uuid.eq(collections::org_uuid) + .and(users_organizations::user_uuid.eq(user_id.clone())) + )) + .left_join(users_collections::table.on( + users_collections::collection_uuid.eq(ciphers_collections::collection_uuid) + .and(users_collections::user_uuid.eq(user_id.clone())) + )) + .filter(ciphers_collections::cipher_uuid.eq(&self.uuid)) + .filter(users_organizations::access_all.eq(true) // User has access all + .or(users_collections::user_uuid.eq(user_id)) // User has access to collection ) - )) - .left_join(users_collections::table.on( - users_collections::collection_uuid.eq(ciphers_collections::collection_uuid).and( - users_collections::user_uuid.eq(user_id.clone()) - ) - )) - .filter(ciphers_collections::cipher_uuid.eq(&self.uuid)) - .filter(users_collections::user_uuid.eq(user_id).or( // User has access to collection - users_organizations::access_all.eq(true).or( // User has access all - users_organizations::atype.le(UserOrgType::Admin as i32) // User is admin or owner - ) - )) - .select(ciphers_collections::collection_uuid) - .load::(conn).unwrap_or_default() - }} + .select(ciphers_collections::collection_uuid) + .load::(conn).unwrap_or_default() + }} + } } /// Return a Vec with (cipher_uuid, collection_uuid)