|
|
@ -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,
|
|
|
|