From b89648a1363f805b10e5d7d1838720446aca01f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johny=20Jim=C3=A9nez?= Date: Wed, 29 Apr 2026 15:58:39 -0500 Subject: [PATCH] Replace organization_uuid unwrap with proper error handling (#6936) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The collection update endpoints (post_collections_update and post_collections_admin) call .unwrap() on cipher.organization_uuid in four places. If a user-owned cipher without an organization somehow reaches these code paths, the server would panic. Extract the organization UUID early with a descriptive error message instead of relying on .unwrap(), preventing potential panics and providing a clear API error response. Co-authored-by: Daniel GarcĂ­a --- src/api/core/ciphers.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index f2fc9fe3..43e555e2 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -814,12 +814,16 @@ async fn post_collections_update( err!("Collection cannot be changed") } + let Some(ref org_uuid) = cipher.organization_uuid else { + err!("Cipher is not owned by an organization") + }; + let posted_collections = HashSet::::from_iter(data.collection_ids); let current_collections = HashSet::::from_iter(cipher.get_collections(headers.user.uuid.clone(), &conn).await); for collection in posted_collections.symmetric_difference(¤t_collections) { - match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &conn).await { + match Collection::find_by_uuid_and_org(collection, org_uuid, &conn).await { None => err!("Invalid collection ID provided"), Some(collection) => { if collection.is_writable_by_user(&headers.user.uuid, &conn).await { @@ -850,7 +854,7 @@ async fn post_collections_update( log_event( EventType::CipherUpdatedCollections as i32, &cipher.uuid, - &cipher.organization_uuid.clone().unwrap(), + org_uuid, &headers.user.uuid, headers.device.atype, &headers.ip.ip, @@ -890,12 +894,16 @@ async fn post_collections_admin( err!("Collection cannot be changed") } + let Some(ref org_uuid) = cipher.organization_uuid else { + err!("Cipher is not owned by an organization") + }; + let posted_collections = HashSet::::from_iter(data.collection_ids); let current_collections = HashSet::::from_iter(cipher.get_admin_collections(headers.user.uuid.clone(), &conn).await); for collection in posted_collections.symmetric_difference(¤t_collections) { - match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &conn).await { + match Collection::find_by_uuid_and_org(collection, org_uuid, &conn).await { None => err!("Invalid collection ID provided"), Some(collection) => { if collection.is_writable_by_user(&headers.user.uuid, &conn).await { @@ -926,7 +934,7 @@ async fn post_collections_admin( log_event( EventType::CipherUpdatedCollections as i32, &cipher.uuid, - &cipher.organization_uuid.unwrap(), + org_uuid, &headers.user.uuid, headers.device.atype, &headers.ip.ip,