|
|
|
@ -14,7 +14,7 @@ use crate::auth::ClientVersion; |
|
|
|
use crate::util::{save_temp_file, NumberOrString}; |
|
|
|
use crate::{ |
|
|
|
api::{self, core::log_event, EmptyResult, JsonResult, Notify, PasswordOrOtpData, UpdateType}, |
|
|
|
auth::Headers, |
|
|
|
auth::{Headers, OrgIdGuard, OwnerHeaders}, |
|
|
|
config::PathType, |
|
|
|
crypto, |
|
|
|
db::{ |
|
|
|
@ -86,7 +86,8 @@ pub fn routes() -> Vec<Route> { |
|
|
|
restore_cipher_put_admin, |
|
|
|
restore_cipher_selected, |
|
|
|
restore_cipher_selected_admin, |
|
|
|
delete_all, |
|
|
|
purge_org_vault, |
|
|
|
purge_personal_vault, |
|
|
|
move_cipher_selected, |
|
|
|
move_cipher_selected_put, |
|
|
|
put_collections2_update, |
|
|
|
@ -1642,65 +1643,73 @@ struct OrganizationIdData { |
|
|
|
org_id: OrganizationId, |
|
|
|
} |
|
|
|
|
|
|
|
// Use the OrgIdGuard here, to ensure there an organization id present.
|
|
|
|
// If there is no organization id present, it should be forwarded to purge_personal_vault.
|
|
|
|
// This guard needs to be the first argument, else OwnerHeaders will be triggered which will logout the user.
|
|
|
|
#[post("/ciphers/purge?<organization..>", data = "<data>")] |
|
|
|
async fn delete_all( |
|
|
|
organization: Option<OrganizationIdData>, |
|
|
|
async fn purge_org_vault( |
|
|
|
_org_id_guard: OrgIdGuard, |
|
|
|
organization: OrganizationIdData, |
|
|
|
data: Json<PasswordOrOtpData>, |
|
|
|
headers: Headers, |
|
|
|
headers: OwnerHeaders, |
|
|
|
conn: DbConn, |
|
|
|
nt: Notify<'_>, |
|
|
|
) -> EmptyResult { |
|
|
|
if organization.org_id != headers.org_id { |
|
|
|
err!("Organization not found", "Organization id's do not match"); |
|
|
|
} |
|
|
|
|
|
|
|
let data: PasswordOrOtpData = data.into_inner(); |
|
|
|
let mut user = headers.user; |
|
|
|
let user = headers.user; |
|
|
|
|
|
|
|
data.validate(&user, true, &conn).await?; |
|
|
|
|
|
|
|
match organization { |
|
|
|
Some(org_data) => { |
|
|
|
// Organization ID in query params, purging organization vault
|
|
|
|
match Membership::find_by_user_and_org(&user.uuid, &org_data.org_id, &conn).await { |
|
|
|
None => err!("You don't have permission to purge the organization vault"), |
|
|
|
Some(member) => { |
|
|
|
if member.atype == MembershipType::Owner { |
|
|
|
Cipher::delete_all_by_organization(&org_data.org_id, &conn).await?; |
|
|
|
nt.send_user_update(UpdateType::SyncVault, &user, &headers.device.push_uuid, &conn).await; |
|
|
|
|
|
|
|
log_event( |
|
|
|
EventType::OrganizationPurgedVault as i32, |
|
|
|
&org_data.org_id, |
|
|
|
&org_data.org_id, |
|
|
|
&user.uuid, |
|
|
|
headers.device.atype, |
|
|
|
&headers.ip.ip, |
|
|
|
&conn, |
|
|
|
) |
|
|
|
.await; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
} else { |
|
|
|
err!("You don't have permission to purge the organization vault"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
None => { |
|
|
|
// No organization ID in query params, purging user vault
|
|
|
|
// Delete ciphers and their attachments
|
|
|
|
for cipher in Cipher::find_owned_by_user(&user.uuid, &conn).await { |
|
|
|
cipher.delete(&conn).await?; |
|
|
|
} |
|
|
|
|
|
|
|
// Delete folders
|
|
|
|
for f in Folder::find_by_user(&user.uuid, &conn).await { |
|
|
|
f.delete(&conn).await?; |
|
|
|
} |
|
|
|
|
|
|
|
user.update_revision(&conn).await?; |
|
|
|
match Membership::find_confirmed_by_user_and_org(&user.uuid, &organization.org_id, &conn).await { |
|
|
|
Some(member) if member.atype == MembershipType::Owner => { |
|
|
|
Cipher::delete_all_by_organization(&organization.org_id, &conn).await?; |
|
|
|
nt.send_user_update(UpdateType::SyncVault, &user, &headers.device.push_uuid, &conn).await; |
|
|
|
|
|
|
|
log_event( |
|
|
|
EventType::OrganizationPurgedVault as i32, |
|
|
|
&organization.org_id, |
|
|
|
&organization.org_id, |
|
|
|
&user.uuid, |
|
|
|
headers.device.atype, |
|
|
|
&headers.ip.ip, |
|
|
|
&conn, |
|
|
|
) |
|
|
|
.await; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
_ => err!("You don't have permission to purge the organization vault"), |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#[post("/ciphers/purge", data = "<data>")] |
|
|
|
async fn purge_personal_vault( |
|
|
|
data: Json<PasswordOrOtpData>, |
|
|
|
headers: Headers, |
|
|
|
conn: DbConn, |
|
|
|
nt: Notify<'_>, |
|
|
|
) -> EmptyResult { |
|
|
|
let data: PasswordOrOtpData = data.into_inner(); |
|
|
|
let mut user = headers.user; |
|
|
|
|
|
|
|
data.validate(&user, true, &conn).await?; |
|
|
|
|
|
|
|
for cipher in Cipher::find_owned_by_user(&user.uuid, &conn).await { |
|
|
|
cipher.delete(&conn).await?; |
|
|
|
} |
|
|
|
|
|
|
|
for f in Folder::find_by_user(&user.uuid, &conn).await { |
|
|
|
f.delete(&conn).await?; |
|
|
|
} |
|
|
|
|
|
|
|
user.update_revision(&conn).await?; |
|
|
|
nt.send_user_update(UpdateType::SyncVault, &user, &headers.device.push_uuid, &conn).await; |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
|
|
|
|
#[derive(PartialEq)] |
|
|
|
|