@ -1405,7 +1405,7 @@ async fn delete_attachment_admin(
#[ post( " /ciphers/<cipher_id>/delete " ) ]
async fn delete_cipher_post ( cipher_id : CipherId , headers : Headers , mut conn : DbConn , nt : Notify < '_ > ) -> EmptyResult {
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , fals e, & nt ) . await
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , & CipherDeleteOptions ::HardSingl e, & nt ) . await
// permanent delete
}
@ -1416,13 +1416,13 @@ async fn delete_cipher_post_admin(
mut conn : DbConn ,
nt : Notify < '_ > ,
) -> EmptyResult {
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , fals e, & nt ) . await
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , & CipherDeleteOptions ::HardSingl e, & nt ) . await
// permanent delete
}
#[ put( " /ciphers/<cipher_id>/delete " ) ]
async fn delete_cipher_put ( cipher_id : CipherId , headers : Headers , mut conn : DbConn , nt : Notify < '_ > ) -> EmptyResult {
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , tru e, & nt ) . await
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , & CipherDeleteOptions ::SoftSingl e, & nt ) . await
// soft delete
}
@ -1433,18 +1433,19 @@ async fn delete_cipher_put_admin(
mut conn : DbConn ,
nt : Notify < '_ > ,
) -> EmptyResult {
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , true , & nt ) . await
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , & CipherDeleteOptions ::SoftSingle , & nt ) . await
// soft delete
}
#[ delete( " /ciphers/<cipher_id> " ) ]
async fn delete_cipher ( cipher_id : CipherId , headers : Headers , mut conn : DbConn , nt : Notify < '_ > ) -> EmptyResult {
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , fals e, & nt ) . await
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , & CipherDeleteOptions ::HardSingl e, & nt ) . await
// permanent delete
}
#[ delete( " /ciphers/<cipher_id>/admin " ) ]
async fn delete_cipher_admin ( cipher_id : CipherId , headers : Headers , mut conn : DbConn , nt : Notify < '_ > ) -> EmptyResult {
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , fals e, & nt ) . await
_delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , & CipherDeleteOptions ::HardSingl e, & nt ) . await
// permanent delete
}
@ -1455,7 +1456,8 @@ async fn delete_cipher_selected(
conn : DbConn ,
nt : Notify < '_ > ,
) -> EmptyResult {
_delete_multiple_ciphers ( data , headers , conn , false , nt ) . await // permanent delete
_delete_multiple_ciphers ( data , headers , conn , CipherDeleteOptions ::HardMulti , nt ) . await
// permanent delete
}
#[ post( " /ciphers/delete " , data = " <data> " ) ]
@ -1465,7 +1467,8 @@ async fn delete_cipher_selected_post(
conn : DbConn ,
nt : Notify < '_ > ,
) -> EmptyResult {
_delete_multiple_ciphers ( data , headers , conn , false , nt ) . await // permanent delete
_delete_multiple_ciphers ( data , headers , conn , CipherDeleteOptions ::HardMulti , nt ) . await
// permanent delete
}
#[ put( " /ciphers/delete " , data = " <data> " ) ]
@ -1475,7 +1478,8 @@ async fn delete_cipher_selected_put(
conn : DbConn ,
nt : Notify < '_ > ,
) -> EmptyResult {
_delete_multiple_ciphers ( data , headers , conn , true , nt ) . await // soft delete
_delete_multiple_ciphers ( data , headers , conn , CipherDeleteOptions ::SoftMulti , nt ) . await
// soft delete
}
#[ delete( " /ciphers/admin " , data = " <data> " ) ]
@ -1485,7 +1489,8 @@ async fn delete_cipher_selected_admin(
conn : DbConn ,
nt : Notify < '_ > ,
) -> EmptyResult {
_delete_multiple_ciphers ( data , headers , conn , false , nt ) . await // permanent delete
_delete_multiple_ciphers ( data , headers , conn , CipherDeleteOptions ::HardMulti , nt ) . await
// permanent delete
}
#[ post( " /ciphers/delete-admin " , data = " <data> " ) ]
@ -1495,7 +1500,8 @@ async fn delete_cipher_selected_post_admin(
conn : DbConn ,
nt : Notify < '_ > ,
) -> EmptyResult {
_delete_multiple_ciphers ( data , headers , conn , false , nt ) . await // permanent delete
_delete_multiple_ciphers ( data , headers , conn , CipherDeleteOptions ::HardMulti , nt ) . await
// permanent delete
}
#[ put( " /ciphers/delete-admin " , data = " <data> " ) ]
@ -1505,7 +1511,8 @@ async fn delete_cipher_selected_put_admin(
conn : DbConn ,
nt : Notify < '_ > ,
) -> EmptyResult {
_delete_multiple_ciphers ( data , headers , conn , true , nt ) . await // soft delete
_delete_multiple_ciphers ( data , headers , conn , CipherDeleteOptions ::SoftMulti , nt ) . await
// soft delete
}
#[ put( " /ciphers/<cipher_id>/restore " ) ]
@ -1659,11 +1666,19 @@ async fn delete_all(
}
}
#[ derive(PartialEq) ]
pub enum CipherDeleteOptions {
SoftSingle ,
SoftMulti ,
HardSingle ,
HardMulti ,
}
async fn _delete_cipher_by_uuid (
cipher_id : & CipherId ,
headers : & Headers ,
conn : & mut DbConn ,
soft_delete : bool ,
delete_options : & CipherDeleteOptions ,
nt : & Notify < '_ > ,
) -> EmptyResult {
let Some ( mut cipher ) = Cipher ::find_by_uuid ( cipher_id , conn ) . await else {
@ -1674,35 +1689,42 @@ async fn _delete_cipher_by_uuid(
err ! ( "Cipher can't be deleted by user" )
}
if soft_delete {
if * delete_options = = CipherDeleteOptions ::SoftSingle | | * delete_options = = CipherDeleteOptions ::SoftMulti {
cipher . deleted_at = Some ( Utc ::now ( ) . naive_utc ( ) ) ;
cipher . save ( conn ) . await ? ;
nt . send_cipher_update (
UpdateType ::SyncCipherUpdate ,
& cipher ,
& cipher . update_users_revision ( conn ) . await ,
& headers . device ,
None ,
conn ,
)
. await ;
if * delete_options = = CipherDeleteOptions ::SoftSingle {
nt . send_cipher_update (
UpdateType ::SyncCipherUpdate ,
& cipher ,
& cipher . update_users_revision ( conn ) . await ,
& headers . device ,
None ,
conn ,
)
. await ;
}
} else {
cipher . delete ( conn ) . await ? ;
nt . send_cipher_update (
UpdateType ::SyncCipherDelete ,
& cipher ,
& cipher . update_users_revision ( conn ) . await ,
& headers . device ,
None ,
conn ,
)
. await ;
if * delete_options = = CipherDeleteOptions ::HardSingle {
nt . send_cipher_update (
UpdateType ::SyncLoginDelete ,
& cipher ,
& cipher . update_users_revision ( conn ) . await ,
& headers . device ,
None ,
conn ,
)
. await ;
}
}
if let Some ( org_id ) = cipher . organization_uuid {
let event_type = match soft_delete {
true = > EventType ::CipherSoftDeleted as i32 ,
false = > EventType ::CipherDeleted as i32 ,
let event_type = if * delete_options = = CipherDeleteOptions ::SoftSingle
| | * delete_options = = CipherDeleteOptions ::SoftMulti
{
EventType ::CipherSoftDeleted as i32
} else {
EventType ::CipherDeleted as i32
} ;
log_event ( event_type , & cipher . uuid , & org_id , & headers . user . uuid , headers . device . atype , & headers . ip . ip , conn )
@ -1722,17 +1744,20 @@ async fn _delete_multiple_ciphers(
data : Json < CipherIdsData > ,
headers : Headers ,
mut conn : DbConn ,
soft_delete : bool ,
delete_options : CipherDeleteOptions ,
nt : Notify < '_ > ,
) -> EmptyResult {
let data = data . into_inner ( ) ;
for cipher_id in data . ids {
if let error @ Err ( _ ) = _delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , soft_ delete, & nt ) . await {
if let error @ Err ( _ ) = _delete_cipher_by_uuid ( & cipher_id , & headers , & mut conn , & delete_options , & nt ) . await {
return error ;
} ;
}
// Multi delete 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 , & mut conn ) . await ;
Ok ( ( ) )
}