|
@ -310,7 +310,8 @@ async fn post_ciphers( |
|
|
data.LastKnownRevisionDate = None; |
|
|
data.LastKnownRevisionDate = None; |
|
|
|
|
|
|
|
|
let mut cipher = Cipher::new(data.Type, data.Name.clone()); |
|
|
let mut cipher = Cipher::new(data.Type, data.Name.clone()); |
|
|
update_cipher_from_data(&mut cipher, data, &headers, false, &mut conn, &ip, &nt, UpdateType::CipherCreate).await?; |
|
|
update_cipher_from_data(&mut cipher, data, &headers, false, &mut conn, &ip, &nt, UpdateType::SyncCipherCreate) |
|
|
|
|
|
.await?; |
|
|
|
|
|
|
|
|
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &mut conn).await)) |
|
|
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &mut conn).await)) |
|
|
} |
|
|
} |
|
@ -415,7 +416,14 @@ pub async fn update_cipher_from_data( |
|
|
for (id, attachment) in attachments { |
|
|
for (id, attachment) in attachments { |
|
|
let mut saved_att = match Attachment::find_by_id(&id, conn).await { |
|
|
let mut saved_att = match Attachment::find_by_id(&id, conn).await { |
|
|
Some(att) => att, |
|
|
Some(att) => att, |
|
|
None => err!("Attachment doesn't exist"), |
|
|
None => { |
|
|
|
|
|
// Warn and continue here.
|
|
|
|
|
|
// A missing attachment means it was removed via an other client.
|
|
|
|
|
|
// Also the Desktop Client supports removing attachments and save an update afterwards.
|
|
|
|
|
|
// Bitwarden it self ignores these mismatches server side.
|
|
|
|
|
|
warn!("Attachment {id} doesn't exist"); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
if saved_att.cipher_uuid != cipher.uuid { |
|
|
if saved_att.cipher_uuid != cipher.uuid { |
|
@ -482,8 +490,8 @@ pub async fn update_cipher_from_data( |
|
|
// Only log events for organizational ciphers
|
|
|
// Only log events for organizational ciphers
|
|
|
if let Some(org_uuid) = &cipher.organization_uuid { |
|
|
if let Some(org_uuid) = &cipher.organization_uuid { |
|
|
let event_type = match (&ut, transfer_cipher) { |
|
|
let event_type = match (&ut, transfer_cipher) { |
|
|
(UpdateType::CipherCreate, true) => EventType::CipherCreated, |
|
|
(UpdateType::SyncCipherCreate, true) => EventType::CipherCreated, |
|
|
(UpdateType::CipherUpdate, true) => EventType::CipherShared, |
|
|
(UpdateType::SyncCipherUpdate, true) => EventType::CipherShared, |
|
|
(_, _) => EventType::CipherUpdated, |
|
|
(_, _) => EventType::CipherUpdated, |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
@ -499,7 +507,7 @@ pub async fn update_cipher_from_data( |
|
|
.await; |
|
|
.await; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
nt.send_cipher_update(ut, cipher, &cipher.update_users_revision(conn).await).await; |
|
|
nt.send_cipher_update(ut, cipher, &cipher.update_users_revision(conn).await, &headers.device.uuid).await; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Ok(()) |
|
|
Ok(()) |
|
@ -562,7 +570,7 @@ async fn post_ciphers_import( |
|
|
|
|
|
|
|
|
let mut user = headers.user; |
|
|
let mut user = headers.user; |
|
|
user.update_revision(&mut conn).await?; |
|
|
user.update_revision(&mut conn).await?; |
|
|
nt.send_user_update(UpdateType::Vault, &user).await; |
|
|
nt.send_user_update(UpdateType::SyncVault, &user).await; |
|
|
Ok(()) |
|
|
Ok(()) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -628,7 +636,8 @@ async fn put_cipher( |
|
|
err!("Cipher is not write accessible") |
|
|
err!("Cipher is not write accessible") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
update_cipher_from_data(&mut cipher, data, &headers, false, &mut conn, &ip, &nt, UpdateType::CipherUpdate).await?; |
|
|
update_cipher_from_data(&mut cipher, data, &headers, false, &mut conn, &ip, &nt, UpdateType::SyncCipherUpdate) |
|
|
|
|
|
.await?; |
|
|
|
|
|
|
|
|
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &mut conn).await)) |
|
|
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &mut conn).await)) |
|
|
} |
|
|
} |
|
@ -850,9 +859,9 @@ async fn share_cipher_by_uuid( |
|
|
|
|
|
|
|
|
// When LastKnownRevisionDate is None, it is a new cipher, so send CipherCreate.
|
|
|
// When LastKnownRevisionDate is None, it is a new cipher, so send CipherCreate.
|
|
|
let ut = if data.Cipher.LastKnownRevisionDate.is_some() { |
|
|
let ut = if data.Cipher.LastKnownRevisionDate.is_some() { |
|
|
UpdateType::CipherUpdate |
|
|
UpdateType::SyncCipherUpdate |
|
|
} else { |
|
|
} else { |
|
|
UpdateType::CipherCreate |
|
|
UpdateType::SyncCipherCreate |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
update_cipher_from_data(&mut cipher, data.Cipher, headers, shared_to_collection, conn, ip, nt, ut).await?; |
|
|
update_cipher_from_data(&mut cipher, data.Cipher, headers, shared_to_collection, conn, ip, nt, ut).await?; |
|
@ -1054,7 +1063,13 @@ async fn save_attachment( |
|
|
data.data.move_copy_to(file_path).await? |
|
|
data.data.move_copy_to(file_path).await? |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &cipher.update_users_revision(&mut conn).await).await; |
|
|
nt.send_cipher_update( |
|
|
|
|
|
UpdateType::SyncCipherUpdate, |
|
|
|
|
|
&cipher, |
|
|
|
|
|
&cipher.update_users_revision(&mut conn).await, |
|
|
|
|
|
&headers.device.uuid, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
|
|
|
|
|
|
if let Some(org_uuid) = &cipher.organization_uuid { |
|
|
if let Some(org_uuid) = &cipher.organization_uuid { |
|
|
log_event( |
|
|
log_event( |
|
@ -1390,7 +1405,7 @@ async fn move_cipher_selected( |
|
|
// Move cipher
|
|
|
// Move cipher
|
|
|
cipher.move_to_folder(data.FolderId.clone(), &user_uuid, &mut conn).await?; |
|
|
cipher.move_to_folder(data.FolderId.clone(), &user_uuid, &mut conn).await?; |
|
|
|
|
|
|
|
|
nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &[user_uuid.clone()]).await; |
|
|
nt.send_cipher_update(UpdateType::SyncCipherUpdate, &cipher, &[user_uuid.clone()], &headers.device.uuid).await; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Ok(()) |
|
|
Ok(()) |
|
@ -1438,7 +1453,7 @@ async fn delete_all( |
|
|
Some(user_org) => { |
|
|
Some(user_org) => { |
|
|
if user_org.atype == UserOrgType::Owner { |
|
|
if user_org.atype == UserOrgType::Owner { |
|
|
Cipher::delete_all_by_organization(&org_data.org_id, &mut conn).await?; |
|
|
Cipher::delete_all_by_organization(&org_data.org_id, &mut conn).await?; |
|
|
nt.send_user_update(UpdateType::Vault, &user).await; |
|
|
nt.send_user_update(UpdateType::SyncVault, &user).await; |
|
|
|
|
|
|
|
|
log_event( |
|
|
log_event( |
|
|
EventType::OrganizationPurgedVault as i32, |
|
|
EventType::OrganizationPurgedVault as i32, |
|
@ -1471,7 +1486,7 @@ async fn delete_all( |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
user.update_revision(&mut conn).await?; |
|
|
user.update_revision(&mut conn).await?; |
|
|
nt.send_user_update(UpdateType::Vault, &user).await; |
|
|
nt.send_user_update(UpdateType::SyncVault, &user).await; |
|
|
Ok(()) |
|
|
Ok(()) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -1497,10 +1512,22 @@ async fn _delete_cipher_by_uuid( |
|
|
if soft_delete { |
|
|
if soft_delete { |
|
|
cipher.deleted_at = Some(Utc::now().naive_utc()); |
|
|
cipher.deleted_at = Some(Utc::now().naive_utc()); |
|
|
cipher.save(conn).await?; |
|
|
cipher.save(conn).await?; |
|
|
nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &cipher.update_users_revision(conn).await).await; |
|
|
nt.send_cipher_update( |
|
|
|
|
|
UpdateType::SyncCipherUpdate, |
|
|
|
|
|
&cipher, |
|
|
|
|
|
&cipher.update_users_revision(conn).await, |
|
|
|
|
|
&headers.device.uuid, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
} else { |
|
|
} else { |
|
|
cipher.delete(conn).await?; |
|
|
cipher.delete(conn).await?; |
|
|
nt.send_cipher_update(UpdateType::CipherDelete, &cipher, &cipher.update_users_revision(conn).await).await; |
|
|
nt.send_cipher_update( |
|
|
|
|
|
UpdateType::SyncCipherDelete, |
|
|
|
|
|
&cipher, |
|
|
|
|
|
&cipher.update_users_revision(conn).await, |
|
|
|
|
|
&headers.device.uuid, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if let Some(org_uuid) = cipher.organization_uuid { |
|
|
if let Some(org_uuid) = cipher.organization_uuid { |
|
@ -1562,7 +1589,13 @@ async fn _restore_cipher_by_uuid( |
|
|
cipher.deleted_at = None; |
|
|
cipher.deleted_at = None; |
|
|
cipher.save(conn).await?; |
|
|
cipher.save(conn).await?; |
|
|
|
|
|
|
|
|
nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &cipher.update_users_revision(conn).await).await; |
|
|
nt.send_cipher_update( |
|
|
|
|
|
UpdateType::SyncCipherUpdate, |
|
|
|
|
|
&cipher, |
|
|
|
|
|
&cipher.update_users_revision(conn).await, |
|
|
|
|
|
&headers.device.uuid, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
if let Some(org_uuid) = &cipher.organization_uuid { |
|
|
if let Some(org_uuid) = &cipher.organization_uuid { |
|
|
log_event( |
|
|
log_event( |
|
|
EventType::CipherRestored as i32, |
|
|
EventType::CipherRestored as i32, |
|
@ -1639,7 +1672,13 @@ async fn _delete_cipher_attachment_by_id( |
|
|
|
|
|
|
|
|
// Delete attachment
|
|
|
// Delete attachment
|
|
|
attachment.delete(conn).await?; |
|
|
attachment.delete(conn).await?; |
|
|
nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &cipher.update_users_revision(conn).await).await; |
|
|
nt.send_cipher_update( |
|
|
|
|
|
UpdateType::SyncCipherUpdate, |
|
|
|
|
|
&cipher, |
|
|
|
|
|
&cipher.update_users_revision(conn).await, |
|
|
|
|
|
&headers.device.uuid, |
|
|
|
|
|
) |
|
|
|
|
|
.await; |
|
|
if let Some(org_uuid) = cipher.organization_uuid { |
|
|
if let Some(org_uuid) = cipher.organization_uuid { |
|
|
log_event( |
|
|
log_event( |
|
|
EventType::CipherAttachmentDeleted as i32, |
|
|
EventType::CipherAttachmentDeleted as i32, |
|
|