diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index aecbe28a..1c89aed7 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -1924,11 +1924,21 @@ impl CipherSyncData { // Generate a HashMap with the collections_uuid as key and the CollectionGroup record let user_collections_groups: HashMap = if CONFIG.org_groups_enabled() { - CollectionGroup::find_by_user(user_id, conn) - .await - .into_iter() - .map(|collection_group| (collection_group.collections_uuid.clone(), collection_group)) - .collect() + CollectionGroup::find_by_user(user_id, conn).await.into_iter().fold( + HashMap::new(), + |mut combined_permissions, cg| { + combined_permissions + .entry(cg.collections_uuid.clone()) + .and_modify(|existing| { + // Combine permissions: take the most permissive settings. + existing.read_only &= cg.read_only; // false if ANY group allows write + existing.hide_passwords &= cg.hide_passwords; // false if ANY group allows password view + existing.manage |= cg.manage; // true if ANY group allows manage + }) + .or_insert(cg); + combined_permissions + }, + ) } else { HashMap::new() }; diff --git a/src/db/models/collection.rs b/src/db/models/collection.rs index 4f192a25..c14c5946 100644 --- a/src/db/models/collection.rs +++ b/src/db/models/collection.rs @@ -97,13 +97,13 @@ impl Collection { ( cu.read_only, cu.hide_passwords, - cu.manage || (is_manager && !cu.read_only && !cu.hide_passwords), + is_manager && (cu.manage || (!cu.read_only && !cu.hide_passwords)), ) } else if let Some(cg) = cipher_sync_data.user_collections_groups.get(&self.uuid) { ( cg.read_only, cg.hide_passwords, - cg.manage || (is_manager && !cg.read_only && !cg.hide_passwords), + is_manager && (cg.manage || (!cg.read_only && !cg.hide_passwords)), ) } else { (false, false, false) @@ -114,7 +114,9 @@ impl Collection { } else { match Membership::find_confirmed_by_user_and_org(user_uuid, &self.org_uuid, conn).await { Some(m) if m.has_full_access() => (false, false, m.atype >= MembershipType::Manager), - Some(_) if self.is_manageable_by_user(user_uuid, conn).await => (false, false, true), + Some(m) if m.atype == MembershipType::Manager && self.is_manageable_by_user(user_uuid, conn).await => { + (false, false, true) + } Some(m) => { let is_manager = m.atype == MembershipType::Manager; let read_only = !self.is_writable_by_user(user_uuid, conn).await;