mirror of
https://github.com/dani-garcia/vaultwarden.wiki.git
synced 2026-10-26 08:36:49 +02:00
Fix bulk cipher share response for SDK clients (#7831)
* Fix bulk cipher share response for SDK clients * Simplify cipher sharing code
This commit is contained in:
1 file changed
+60
-6
+60
-6
@@ -1018,14 +1018,53 @@ struct ShareSelectedCipherData {
|
|||||||
collection_ids: Vec<CollectionId>,
|
collection_ids: Vec<CollectionId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A bulk share returns cipherMini models, not the cipherDetails models used by
|
||||||
|
// the single-share route. Keep the encrypted legacy fields and a future v2
|
||||||
|
// `data` blob, but do not expose details-only fields in this response.
|
||||||
|
fn cipher_mini_from_json(mut cipher: Value) -> Value {
|
||||||
|
const FIELDS: &[&str] = &[
|
||||||
|
"id",
|
||||||
|
"organizationId",
|
||||||
|
"type",
|
||||||
|
"data",
|
||||||
|
"partialData",
|
||||||
|
"name",
|
||||||
|
"notes",
|
||||||
|
"login",
|
||||||
|
"card",
|
||||||
|
"identity",
|
||||||
|
"secureNote",
|
||||||
|
"sshKey",
|
||||||
|
"bankAccount",
|
||||||
|
"driversLicense",
|
||||||
|
"passport",
|
||||||
|
"fields",
|
||||||
|
"passwordHistory",
|
||||||
|
"attachments",
|
||||||
|
"organizationUseTotp",
|
||||||
|
"revisionDate",
|
||||||
|
"creationDate",
|
||||||
|
"deletedDate",
|
||||||
|
"reprompt",
|
||||||
|
"key",
|
||||||
|
];
|
||||||
|
|
||||||
|
let Some(object) = cipher.as_object_mut() else {
|
||||||
|
return json!({ "object": "cipherMini" });
|
||||||
|
};
|
||||||
|
object.retain(|field, _| FIELDS.contains(&field.as_str()));
|
||||||
|
object.insert("object".into(), "cipherMini".into());
|
||||||
|
cipher
|
||||||
|
}
|
||||||
|
|
||||||
#[put("/ciphers/share", data = "<data>")]
|
#[put("/ciphers/share", data = "<data>")]
|
||||||
async fn put_cipher_share_selected(
|
async fn put_cipher_share_selected(
|
||||||
data: Json<ShareSelectedCipherData>,
|
data: Json<ShareSelectedCipherData>,
|
||||||
headers: Headers,
|
headers: Headers,
|
||||||
conn: DbConn,
|
conn: DbConn,
|
||||||
nt: Notify<'_>,
|
nt: Notify<'_>,
|
||||||
) -> EmptyResult {
|
) -> JsonResult {
|
||||||
let mut data: ShareSelectedCipherData = data.into_inner();
|
let data: ShareSelectedCipherData = data.into_inner();
|
||||||
|
|
||||||
if data.ciphers.is_empty() {
|
if data.ciphers.is_empty() {
|
||||||
err!("You must select at least one cipher.")
|
err!("You must select at least one cipher.")
|
||||||
@@ -1041,23 +1080,38 @@ async fn put_cipher_share_selected(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(cipher) = data.ciphers.pop() {
|
let mut responses = Vec::with_capacity(data.ciphers.len());
|
||||||
|
for cipher in data.ciphers {
|
||||||
let mut shared_cipher_data = ShareCipherData {
|
let mut shared_cipher_data = ShareCipherData {
|
||||||
cipher,
|
cipher,
|
||||||
collection_ids: data.collection_ids.clone(),
|
collection_ids: data.collection_ids.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(id) = shared_cipher_data.cipher.id.take() {
|
if let Some(id) = shared_cipher_data.cipher.id.take() {
|
||||||
share_cipher_by_uuid(&id, shared_cipher_data, &headers, &conn, &nt, Some(UpdateType::None)).await?
|
let response =
|
||||||
|
share_cipher_by_uuid(&id, shared_cipher_data, &headers, &conn, &nt, Some(UpdateType::None)).await?;
|
||||||
|
|
||||||
|
// Like upstream's VisibleToClient, withhold a cipher if sharing it
|
||||||
|
// removed the user's access to it. Only then include its encrypted
|
||||||
|
// mini response; the full single-share response stays internal.
|
||||||
|
if let Some(shared_cipher) = Cipher::find_by_uuid(&id, &conn).await
|
||||||
|
&& shared_cipher.is_accessible_to_user(&headers.user.uuid, &conn).await
|
||||||
|
{
|
||||||
|
responses.push(cipher_mini_from_json(response.into_inner()));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
err!("Request missing ids field")
|
err!("Request missing ids field")
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Multi share actions do not send out a push for each cipher, we need to send a general sync here
|
// Multi share actions do not send out a push for each cipher, we need to send a general sync here
|
||||||
nt.send_user_update(UpdateType::SyncCiphers, &headers.user, headers.device.push_uuid.as_ref(), &conn).await;
|
nt.send_user_update(UpdateType::SyncCiphers, &headers.user, headers.device.push_uuid.as_ref(), &conn).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(Json(json!({
|
||||||
|
"data": responses,
|
||||||
|
"object": "list",
|
||||||
|
"continuationToken": null,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn share_cipher_by_uuid(
|
async fn share_cipher_by_uuid(
|
||||||
|
|||||||
Reference in new issue
Block a user