Browse Source

Fix "Invalid folder" error when client sends empty folderId string

Newer Bitwarden client versions (e.g. browser extension v2026.2.0) send
folderId as "" (empty string) instead of null when "No folder" is selected.
This causes the folder validation to attempt a database lookup with an
empty string, which fails with "Invalid folder" and prevents saving the
cipher.

Normalize empty folderId to None at all three validation points:
- update_cipher_from_data (create/update cipher)
- put_cipher_partial (update cipher details)
- move_cipher_selected (move ciphers to folder)

Fixes #6962
pull/6967/head
easonysliu 3 weeks ago
parent
commit
8869652dad
  1. 20
      src/api/core/ciphers.rs

20
src/api/core/ciphers.rs

@ -448,7 +448,11 @@ pub async fn update_cipher_from_data(
cipher.user_uuid = Some(headers.user.uuid.clone());
}
if let Some(ref folder_id) = data.folder_id {
// Newer Bitwarden clients may send folderId as "" instead of null for "No folder".
// Normalize empty folder_id to None to avoid invalid folder lookup errors.
let folder_id = data.folder_id.filter(|f| !f.is_empty());
if let Some(ref folder_id) = folder_id {
if Folder::find_by_uuid_and_user(folder_id, &headers.user.uuid, conn).await.is_none() {
err!("Invalid folder", "Folder does not exist or belongs to another user");
}
@ -528,7 +532,7 @@ pub async fn update_cipher_from_data(
cipher.reprompt = data.reprompt.filter(|r| *r == RepromptType::None as i32 || *r == RepromptType::Password as i32);
cipher.save(conn).await?;
cipher.move_to_folder(data.folder_id, &headers.user.uuid, conn).await?;
cipher.move_to_folder(folder_id, &headers.user.uuid, conn).await?;
cipher.set_favorite(data.favorite, &headers.user.uuid, conn).await?;
if ut != UpdateType::None {
@ -722,14 +726,16 @@ async fn put_cipher_partial(
err!("Cipher does not exist", "Cipher is not accessible for the current user")
}
if let Some(ref folder_id) = data.folder_id {
let folder_id = data.folder_id.filter(|f| !f.is_empty());
if let Some(ref folder_id) = folder_id {
if Folder::find_by_uuid_and_user(folder_id, &headers.user.uuid, &conn).await.is_none() {
err!("Invalid folder", "Folder does not exist or belongs to another user");
}
}
// Move cipher
cipher.move_to_folder(data.folder_id.clone(), &headers.user.uuid, &conn).await?;
cipher.move_to_folder(folder_id, &headers.user.uuid, &conn).await?;
// Update favorite
cipher.set_favorite(Some(data.favorite), &headers.user.uuid, &conn).await?;
@ -1582,7 +1588,9 @@ async fn move_cipher_selected(
let data = data.into_inner();
let user_id = &headers.user.uuid;
if let Some(ref folder_id) = data.folder_id {
let folder_id = data.folder_id.filter(|f| !f.is_empty());
if let Some(ref folder_id) = folder_id {
if Folder::find_by_uuid_and_user(folder_id, user_id, &conn).await.is_none() {
err!("Invalid folder", "Folder does not exist or belongs to another user");
}
@ -1596,7 +1604,7 @@ async fn move_cipher_selected(
let accessible_ciphers = Cipher::find_by_user_and_ciphers(user_id, &data.ids, &conn).await;
let accessible_ciphers_count = accessible_ciphers.len();
for cipher in accessible_ciphers {
cipher.move_to_folder(data.folder_id.clone(), user_id, &conn).await?;
cipher.move_to_folder(folder_id.clone(), user_id, &conn).await?;
if cipher_count == 1 {
single_cipher = Some(cipher);
}

Loading…
Cancel
Save