Merge branch 'BlackDex-update-notifications'
This commit is contained in:
commit
05a552910c
|
@ -13,7 +13,7 @@ use rocket::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
api::{core::log_event, ApiResult, EmptyResult, JsonResult, NumberOrString},
|
||||
api::{core::log_event, ApiResult, EmptyResult, JsonResult, Notify, NumberOrString, UpdateType},
|
||||
auth::{decode_admin, encode_jwt, generate_admin_claims, ClientIp},
|
||||
config::ConfigBuilder,
|
||||
db::{backup_database, get_sql_server_version, models::*, DbConn, DbConnType},
|
||||
|
@ -365,22 +365,30 @@ async fn delete_user(uuid: String, _token: AdminToken, mut conn: DbConn, ip: Cli
|
|||
}
|
||||
|
||||
#[post("/users/<uuid>/deauth")]
|
||||
async fn deauth_user(uuid: String, _token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
async fn deauth_user(uuid: String, _token: AdminToken, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&uuid, &mut conn).await?;
|
||||
Device::delete_all_by_user(&user.uuid, &mut conn).await?;
|
||||
user.reset_security_stamp();
|
||||
|
||||
user.save(&mut conn).await
|
||||
let save_result = user.save(&mut conn).await;
|
||||
|
||||
nt.send_user_update(UpdateType::LogOut, &user).await;
|
||||
|
||||
save_result
|
||||
}
|
||||
|
||||
#[post("/users/<uuid>/disable")]
|
||||
async fn disable_user(uuid: String, _token: AdminToken, mut conn: DbConn) -> EmptyResult {
|
||||
async fn disable_user(uuid: String, _token: AdminToken, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let mut user = get_user_or_404(&uuid, &mut conn).await?;
|
||||
Device::delete_all_by_user(&user.uuid, &mut conn).await?;
|
||||
user.reset_security_stamp();
|
||||
user.enabled = false;
|
||||
|
||||
user.save(&mut conn).await
|
||||
let save_result = user.save(&mut conn).await;
|
||||
|
||||
nt.send_user_update(UpdateType::LogOut, &user).await;
|
||||
|
||||
save_result
|
||||
}
|
||||
|
||||
#[post("/users/<uuid>/enable")]
|
||||
|
|
|
@ -275,6 +275,7 @@ async fn post_password(
|
|||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
ip: ClientIp,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
let data: ChangePassData = data.into_inner().data;
|
||||
let mut user = headers.user;
|
||||
|
@ -293,7 +294,11 @@ async fn post_password(
|
|||
Some(vec![String::from("post_rotatekey"), String::from("get_contacts"), String::from("get_public_keys")]),
|
||||
);
|
||||
user.akey = data.Key;
|
||||
user.save(&mut conn).await
|
||||
let save_result = user.save(&mut conn).await;
|
||||
|
||||
nt.send_user_update(UpdateType::LogOut, &user).await;
|
||||
|
||||
save_result
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -308,7 +313,7 @@ struct ChangeKdfData {
|
|||
}
|
||||
|
||||
#[post("/accounts/kdf", data = "<data>")]
|
||||
async fn post_kdf(data: JsonUpcase<ChangeKdfData>, headers: Headers, mut conn: DbConn) -> EmptyResult {
|
||||
async fn post_kdf(data: JsonUpcase<ChangeKdfData>, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
|
||||
let data: ChangeKdfData = data.into_inner().data;
|
||||
let mut user = headers.user;
|
||||
|
||||
|
@ -320,7 +325,11 @@ async fn post_kdf(data: JsonUpcase<ChangeKdfData>, headers: Headers, mut conn: D
|
|||
user.client_kdf_type = data.Kdf;
|
||||
user.set_password(&data.NewMasterPasswordHash, None);
|
||||
user.akey = data.Key;
|
||||
user.save(&mut conn).await
|
||||
let save_result = user.save(&mut conn).await;
|
||||
|
||||
nt.send_user_update(UpdateType::LogOut, &user).await;
|
||||
|
||||
save_result
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -388,6 +397,7 @@ async fn post_rotatekey(
|
|||
|
||||
// Prevent triggering cipher updates via WebSockets by settings UpdateType::None
|
||||
// The user sessions are invalidated because all the ciphers were re-encrypted and thus triggering an update could cause issues.
|
||||
// We force the users to logout after the user has been saved to try and prevent these issues.
|
||||
update_cipher_from_data(&mut saved_cipher, cipher_data, &headers, false, &mut conn, &ip, &nt, UpdateType::None)
|
||||
.await?
|
||||
}
|
||||
|
@ -399,11 +409,20 @@ async fn post_rotatekey(
|
|||
user.private_key = Some(data.PrivateKey);
|
||||
user.reset_security_stamp();
|
||||
|
||||
user.save(&mut conn).await
|
||||
let save_result = user.save(&mut conn).await;
|
||||
|
||||
nt.send_user_update(UpdateType::LogOut, &user).await;
|
||||
|
||||
save_result
|
||||
}
|
||||
|
||||
#[post("/accounts/security-stamp", data = "<data>")]
|
||||
async fn post_sstamp(data: JsonUpcase<PasswordData>, headers: Headers, mut conn: DbConn) -> EmptyResult {
|
||||
async fn post_sstamp(
|
||||
data: JsonUpcase<PasswordData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
let data: PasswordData = data.into_inner().data;
|
||||
let mut user = headers.user;
|
||||
|
||||
|
@ -413,7 +432,11 @@ async fn post_sstamp(data: JsonUpcase<PasswordData>, headers: Headers, mut conn:
|
|||
|
||||
Device::delete_all_by_user(&user.uuid, &mut conn).await?;
|
||||
user.reset_security_stamp();
|
||||
user.save(&mut conn).await
|
||||
let save_result = user.save(&mut conn).await;
|
||||
|
||||
nt.send_user_update(UpdateType::LogOut, &user).await;
|
||||
|
||||
save_result
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -465,7 +488,12 @@ struct ChangeEmailData {
|
|||
}
|
||||
|
||||
#[post("/accounts/email", data = "<data>")]
|
||||
async fn post_email(data: JsonUpcase<ChangeEmailData>, headers: Headers, mut conn: DbConn) -> EmptyResult {
|
||||
async fn post_email(
|
||||
data: JsonUpcase<ChangeEmailData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
let data: ChangeEmailData = data.into_inner().data;
|
||||
let mut user = headers.user;
|
||||
|
||||
|
@ -507,8 +535,11 @@ async fn post_email(data: JsonUpcase<ChangeEmailData>, headers: Headers, mut con
|
|||
|
||||
user.set_password(&data.NewMasterPasswordHash, None);
|
||||
user.akey = data.Key;
|
||||
let save_result = user.save(&mut conn).await;
|
||||
|
||||
user.save(&mut conn).await
|
||||
nt.send_user_update(UpdateType::LogOut, &user).await;
|
||||
|
||||
save_result
|
||||
}
|
||||
|
||||
#[post("/accounts/verify-email")]
|
||||
|
|
|
@ -310,7 +310,8 @@ async fn post_ciphers(
|
|||
data.LastKnownRevisionDate = None;
|
||||
|
||||
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))
|
||||
}
|
||||
|
@ -415,7 +416,14 @@ pub async fn update_cipher_from_data(
|
|||
for (id, attachment) in attachments {
|
||||
let mut saved_att = match Attachment::find_by_id(&id, conn).await {
|
||||
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 {
|
||||
|
@ -482,8 +490,8 @@ pub async fn update_cipher_from_data(
|
|||
// Only log events for organizational ciphers
|
||||
if let Some(org_uuid) = &cipher.organization_uuid {
|
||||
let event_type = match (&ut, transfer_cipher) {
|
||||
(UpdateType::CipherCreate, true) => EventType::CipherCreated,
|
||||
(UpdateType::CipherUpdate, true) => EventType::CipherShared,
|
||||
(UpdateType::SyncCipherCreate, true) => EventType::CipherCreated,
|
||||
(UpdateType::SyncCipherUpdate, true) => EventType::CipherShared,
|
||||
(_, _) => EventType::CipherUpdated,
|
||||
};
|
||||
|
||||
|
@ -499,7 +507,7 @@ pub async fn update_cipher_from_data(
|
|||
.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(())
|
||||
|
@ -562,7 +570,7 @@ async fn post_ciphers_import(
|
|||
|
||||
let mut user = headers.user;
|
||||
user.update_revision(&mut conn).await?;
|
||||
nt.send_user_update(UpdateType::Vault, &user).await;
|
||||
nt.send_user_update(UpdateType::SyncVault, &user).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -628,7 +636,8 @@ async fn put_cipher(
|
|||
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))
|
||||
}
|
||||
|
@ -850,9 +859,9 @@ async fn share_cipher_by_uuid(
|
|||
|
||||
// When LastKnownRevisionDate is None, it is a new cipher, so send CipherCreate.
|
||||
let ut = if data.Cipher.LastKnownRevisionDate.is_some() {
|
||||
UpdateType::CipherUpdate
|
||||
UpdateType::SyncCipherUpdate
|
||||
} else {
|
||||
UpdateType::CipherCreate
|
||||
UpdateType::SyncCipherCreate
|
||||
};
|
||||
|
||||
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?
|
||||
}
|
||||
|
||||
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 {
|
||||
log_event(
|
||||
|
@ -1390,7 +1405,7 @@ async fn move_cipher_selected(
|
|||
// Move cipher
|
||||
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(())
|
||||
|
@ -1438,7 +1453,7 @@ async fn delete_all(
|
|||
Some(user_org) => {
|
||||
if user_org.atype == UserOrgType::Owner {
|
||||
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(
|
||||
EventType::OrganizationPurgedVault as i32,
|
||||
|
@ -1471,7 +1486,7 @@ async fn delete_all(
|
|||
}
|
||||
|
||||
user.update_revision(&mut conn).await?;
|
||||
nt.send_user_update(UpdateType::Vault, &user).await;
|
||||
nt.send_user_update(UpdateType::SyncVault, &user).await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1497,10 +1512,22 @@ async fn _delete_cipher_by_uuid(
|
|||
if soft_delete {
|
||||
cipher.deleted_at = Some(Utc::now().naive_utc());
|
||||
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 {
|
||||
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 {
|
||||
|
@ -1562,7 +1589,13 @@ async fn _restore_cipher_by_uuid(
|
|||
cipher.deleted_at = None;
|
||||
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 {
|
||||
log_event(
|
||||
EventType::CipherRestored as i32,
|
||||
|
@ -1639,7 +1672,13 @@ async fn _delete_cipher_attachment_by_id(
|
|||
|
||||
// Delete attachment
|
||||
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 {
|
||||
log_event(
|
||||
EventType::CipherAttachmentDeleted as i32,
|
||||
|
|
|
@ -50,7 +50,7 @@ async fn post_folders(data: JsonUpcase<FolderData>, headers: Headers, mut conn:
|
|||
let mut folder = Folder::new(headers.user.uuid, data.Name);
|
||||
|
||||
folder.save(&mut conn).await?;
|
||||
nt.send_folder_update(UpdateType::FolderCreate, &folder).await;
|
||||
nt.send_folder_update(UpdateType::SyncFolderCreate, &folder, &headers.device.uuid).await;
|
||||
|
||||
Ok(Json(folder.to_json()))
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ async fn put_folder(
|
|||
folder.name = data.Name;
|
||||
|
||||
folder.save(&mut conn).await?;
|
||||
nt.send_folder_update(UpdateType::FolderUpdate, &folder).await;
|
||||
nt.send_folder_update(UpdateType::SyncFolderUpdate, &folder, &headers.device.uuid).await;
|
||||
|
||||
Ok(Json(folder.to_json()))
|
||||
}
|
||||
|
@ -112,6 +112,6 @@ async fn delete_folder(uuid: String, headers: Headers, mut conn: DbConn, nt: Not
|
|||
// Delete the actual folder entry
|
||||
folder.delete(&mut conn).await?;
|
||||
|
||||
nt.send_folder_update(UpdateType::FolderDelete, &folder).await;
|
||||
nt.send_folder_update(UpdateType::SyncFolderDelete, &folder, &headers.device.uuid).await;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -7,8 +7,7 @@ mod organizations;
|
|||
mod sends;
|
||||
pub mod two_factor;
|
||||
|
||||
pub use ciphers::purge_trashed_ciphers;
|
||||
pub use ciphers::{CipherSyncData, CipherSyncType};
|
||||
pub use ciphers::{purge_trashed_ciphers, CipherSyncData, CipherSyncType};
|
||||
pub use emergency_access::{emergency_notification_reminder_job, emergency_request_timeout_job};
|
||||
pub use events::{event_cleanup_job, log_event, log_user_event};
|
||||
pub use sends::purge_sends;
|
||||
|
@ -47,13 +46,11 @@ pub fn events_routes() -> Vec<Route> {
|
|||
//
|
||||
// Move this somewhere else
|
||||
//
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::Catcher;
|
||||
use rocket::Route;
|
||||
use rocket::{serde::json::Json, Catcher, Route};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
api::{JsonResult, JsonUpcase},
|
||||
api::{JsonResult, JsonUpcase, Notify, UpdateType},
|
||||
auth::Headers,
|
||||
db::DbConn,
|
||||
error::Error,
|
||||
|
@ -138,7 +135,12 @@ struct EquivDomainData {
|
|||
}
|
||||
|
||||
#[post("/settings/domains", data = "<data>")]
|
||||
async fn post_eq_domains(data: JsonUpcase<EquivDomainData>, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
async fn post_eq_domains(
|
||||
data: JsonUpcase<EquivDomainData>,
|
||||
headers: Headers,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
let data: EquivDomainData = data.into_inner().data;
|
||||
|
||||
let excluded_globals = data.ExcludedGlobalEquivalentDomains.unwrap_or_default();
|
||||
|
@ -152,12 +154,19 @@ async fn post_eq_domains(data: JsonUpcase<EquivDomainData>, headers: Headers, mu
|
|||
|
||||
user.save(&mut conn).await?;
|
||||
|
||||
nt.send_user_update(UpdateType::SyncSettings, &user).await;
|
||||
|
||||
Ok(Json(json!({})))
|
||||
}
|
||||
|
||||
#[put("/settings/domains", data = "<data>")]
|
||||
async fn put_eq_domains(data: JsonUpcase<EquivDomainData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
post_eq_domains(data, headers, conn).await
|
||||
async fn put_eq_domains(
|
||||
data: JsonUpcase<EquivDomainData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
post_eq_domains(data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[get("/hibp/breach?<username>")]
|
||||
|
|
|
@ -957,6 +957,7 @@ async fn bulk_confirm_invite(
|
|||
headers: AdminHeaders,
|
||||
mut conn: DbConn,
|
||||
ip: ClientIp,
|
||||
nt: Notify<'_>,
|
||||
) -> Json<Value> {
|
||||
let data = data.into_inner().data;
|
||||
|
||||
|
@ -966,7 +967,8 @@ async fn bulk_confirm_invite(
|
|||
for invite in keys {
|
||||
let org_user_id = invite["Id"].as_str().unwrap_or_default();
|
||||
let user_key = invite["Key"].as_str().unwrap_or_default();
|
||||
let err_msg = match _confirm_invite(&org_id, org_user_id, user_key, &headers, &mut conn, &ip).await {
|
||||
let err_msg = match _confirm_invite(&org_id, org_user_id, user_key, &headers, &mut conn, &ip, &nt).await
|
||||
{
|
||||
Ok(_) => String::new(),
|
||||
Err(e) => format!("{:?}", e),
|
||||
};
|
||||
|
@ -998,10 +1000,11 @@ async fn confirm_invite(
|
|||
headers: AdminHeaders,
|
||||
mut conn: DbConn,
|
||||
ip: ClientIp,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
let data = data.into_inner().data;
|
||||
let user_key = data["Key"].as_str().unwrap_or_default();
|
||||
_confirm_invite(&org_id, &org_user_id, user_key, &headers, &mut conn, &ip).await
|
||||
_confirm_invite(&org_id, &org_user_id, user_key, &headers, &mut conn, &ip, &nt).await
|
||||
}
|
||||
|
||||
async fn _confirm_invite(
|
||||
|
@ -1011,6 +1014,7 @@ async fn _confirm_invite(
|
|||
headers: &AdminHeaders,
|
||||
conn: &mut DbConn,
|
||||
ip: &ClientIp,
|
||||
nt: &Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
if key.is_empty() || org_user_id.is_empty() {
|
||||
err!("Key or UserId is not set, unable to process request");
|
||||
|
@ -1069,7 +1073,13 @@ async fn _confirm_invite(
|
|||
mail::send_invite_confirmed(&address, &org_name).await?;
|
||||
}
|
||||
|
||||
user_to_confirm.save(conn).await
|
||||
let save_result = user_to_confirm.save(conn).await;
|
||||
|
||||
if let Some(user) = User::find_by_uuid(&user_to_confirm.user_uuid, conn).await {
|
||||
nt.send_user_update(UpdateType::SyncOrgKeys, &user).await;
|
||||
}
|
||||
|
||||
save_result
|
||||
}
|
||||
|
||||
#[get("/organizations/<org_id>/users/<org_user_id>")]
|
||||
|
@ -1206,12 +1216,13 @@ async fn bulk_delete_user(
|
|||
headers: AdminHeaders,
|
||||
mut conn: DbConn,
|
||||
ip: ClientIp,
|
||||
nt: Notify<'_>,
|
||||
) -> Json<Value> {
|
||||
let data: OrgBulkIds = data.into_inner().data;
|
||||
|
||||
let mut bulk_response = Vec::new();
|
||||
for org_user_id in data.Ids {
|
||||
let err_msg = match _delete_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await {
|
||||
let err_msg = match _delete_user(&org_id, &org_user_id, &headers, &mut conn, &ip, &nt).await {
|
||||
Ok(_) => String::new(),
|
||||
Err(e) => format!("{:?}", e),
|
||||
};
|
||||
|
@ -1239,8 +1250,9 @@ async fn delete_user(
|
|||
headers: AdminHeaders,
|
||||
mut conn: DbConn,
|
||||
ip: ClientIp,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
_delete_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await
|
||||
_delete_user(&org_id, &org_user_id, &headers, &mut conn, &ip, &nt).await
|
||||
}
|
||||
|
||||
#[post("/organizations/<org_id>/users/<org_user_id>/delete")]
|
||||
|
@ -1250,8 +1262,9 @@ async fn post_delete_user(
|
|||
headers: AdminHeaders,
|
||||
mut conn: DbConn,
|
||||
ip: ClientIp,
|
||||
nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
_delete_user(&org_id, &org_user_id, &headers, &mut conn, &ip).await
|
||||
_delete_user(&org_id, &org_user_id, &headers, &mut conn, &ip, &nt).await
|
||||
}
|
||||
|
||||
async fn _delete_user(
|
||||
|
@ -1260,6 +1273,7 @@ async fn _delete_user(
|
|||
headers: &AdminHeaders,
|
||||
conn: &mut DbConn,
|
||||
ip: &ClientIp,
|
||||
nt: &Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
let user_to_delete = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await {
|
||||
Some(user) => user,
|
||||
|
@ -1288,6 +1302,10 @@ async fn _delete_user(
|
|||
)
|
||||
.await;
|
||||
|
||||
if let Some(user) = User::find_by_uuid(&user_to_delete.user_uuid, conn).await {
|
||||
nt.send_user_update(UpdateType::SyncOrgKeys, &user).await;
|
||||
}
|
||||
|
||||
user_to_delete.delete(conn).await
|
||||
}
|
||||
|
||||
|
|
|
@ -355,6 +355,7 @@ async fn post_access(
|
|||
data: JsonUpcase<SendAccessData>,
|
||||
mut conn: DbConn,
|
||||
ip: ClientIp,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
let mut send = match Send::find_by_access_id(&access_id, &mut conn).await {
|
||||
Some(s) => s,
|
||||
|
@ -396,6 +397,8 @@ async fn post_access(
|
|||
|
||||
send.save(&mut conn).await?;
|
||||
|
||||
nt.send_send_update(UpdateType::SyncSendUpdate, &send, &send.update_users_revision(&mut conn).await).await;
|
||||
|
||||
Ok(Json(send.to_json_access(&mut conn).await))
|
||||
}
|
||||
|
||||
|
@ -406,6 +409,7 @@ async fn post_access_file(
|
|||
data: JsonUpcase<SendAccessData>,
|
||||
host: Host,
|
||||
mut conn: DbConn,
|
||||
nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
let mut send = match Send::find_by_uuid(&send_id, &mut conn).await {
|
||||
Some(s) => s,
|
||||
|
@ -444,6 +448,8 @@ async fn post_access_file(
|
|||
|
||||
send.save(&mut conn).await?;
|
||||
|
||||
nt.send_send_update(UpdateType::SyncSendUpdate, &send, &send.update_users_revision(&mut conn).await).await;
|
||||
|
||||
let token_claims = crate::auth::generate_send_claims(&send_id, &file_id);
|
||||
let token = crate::auth::encode_jwt(&token_claims);
|
||||
Ok(Json(json!({
|
||||
|
|
|
@ -164,12 +164,13 @@ impl WebSocketUsers {
|
|||
let data = create_update(
|
||||
vec![("UserId".into(), user.uuid.clone().into()), ("Date".into(), serialize_date(user.updated_at))],
|
||||
ut,
|
||||
None,
|
||||
);
|
||||
|
||||
self.send_update(&user.uuid, &data).await;
|
||||
}
|
||||
|
||||
pub async fn send_folder_update(&self, ut: UpdateType, folder: &Folder) {
|
||||
pub async fn send_folder_update(&self, ut: UpdateType, folder: &Folder, acting_device_uuid: &String) {
|
||||
let data = create_update(
|
||||
vec![
|
||||
("Id".into(), folder.uuid.clone().into()),
|
||||
|
@ -177,12 +178,19 @@ impl WebSocketUsers {
|
|||
("RevisionDate".into(), serialize_date(folder.updated_at)),
|
||||
],
|
||||
ut,
|
||||
Some(acting_device_uuid.into()),
|
||||
);
|
||||
|
||||
self.send_update(&folder.user_uuid, &data).await;
|
||||
}
|
||||
|
||||
pub async fn send_cipher_update(&self, ut: UpdateType, cipher: &Cipher, user_uuids: &[String]) {
|
||||
pub async fn send_cipher_update(
|
||||
&self,
|
||||
ut: UpdateType,
|
||||
cipher: &Cipher,
|
||||
user_uuids: &[String],
|
||||
acting_device_uuid: &String,
|
||||
) {
|
||||
let user_uuid = convert_option(cipher.user_uuid.clone());
|
||||
let org_uuid = convert_option(cipher.organization_uuid.clone());
|
||||
|
||||
|
@ -195,6 +203,7 @@ impl WebSocketUsers {
|
|||
("RevisionDate".into(), serialize_date(cipher.updated_at)),
|
||||
],
|
||||
ut,
|
||||
Some(acting_device_uuid.into()),
|
||||
);
|
||||
|
||||
for uuid in user_uuids {
|
||||
|
@ -212,6 +221,7 @@ impl WebSocketUsers {
|
|||
("RevisionDate".into(), serialize_date(send.revision_date)),
|
||||
],
|
||||
ut,
|
||||
None,
|
||||
);
|
||||
|
||||
for uuid in user_uuids {
|
||||
|
@ -228,14 +238,14 @@ impl WebSocketUsers {
|
|||
"ReceiveMessage", // Target
|
||||
[ // Arguments
|
||||
{
|
||||
"ContextId": "app_id",
|
||||
"ContextId": acting_device_uuid || Nil,
|
||||
"Type": ut as i32,
|
||||
"Payload": {}
|
||||
}
|
||||
]
|
||||
]
|
||||
*/
|
||||
fn create_update(payload: Vec<(Value, Value)>, ut: UpdateType) -> Vec<u8> {
|
||||
fn create_update(payload: Vec<(Value, Value)>, ut: UpdateType, acting_device_uuid: Option<String>) -> Vec<u8> {
|
||||
use rmpv::Value as V;
|
||||
|
||||
let value = V::Array(vec![
|
||||
|
@ -244,7 +254,7 @@ fn create_update(payload: Vec<(Value, Value)>, ut: UpdateType) -> Vec<u8> {
|
|||
V::Nil,
|
||||
"ReceiveMessage".into(),
|
||||
V::Array(vec![V::Map(vec![
|
||||
("ContextId".into(), "app_id".into()),
|
||||
("ContextId".into(), acting_device_uuid.map(|v| v.into()).unwrap_or_else(|| V::Nil)),
|
||||
("Type".into(), (ut as i32).into()),
|
||||
("Payload".into(), payload.into()),
|
||||
])]),
|
||||
|
@ -260,17 +270,17 @@ fn create_ping() -> Vec<u8> {
|
|||
#[allow(dead_code)]
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum UpdateType {
|
||||
CipherUpdate = 0,
|
||||
CipherCreate = 1,
|
||||
LoginDelete = 2,
|
||||
FolderDelete = 3,
|
||||
Ciphers = 4,
|
||||
SyncCipherUpdate = 0,
|
||||
SyncCipherCreate = 1,
|
||||
SyncLoginDelete = 2,
|
||||
SyncFolderDelete = 3,
|
||||
SyncCiphers = 4,
|
||||
|
||||
Vault = 5,
|
||||
OrgKeys = 6,
|
||||
FolderCreate = 7,
|
||||
FolderUpdate = 8,
|
||||
CipherDelete = 9,
|
||||
SyncVault = 5,
|
||||
SyncOrgKeys = 6,
|
||||
SyncFolderCreate = 7,
|
||||
SyncFolderUpdate = 8,
|
||||
SyncCipherDelete = 9,
|
||||
SyncSettings = 10,
|
||||
|
||||
LogOut = 11,
|
||||
|
@ -279,6 +289,9 @@ pub enum UpdateType {
|
|||
SyncSendUpdate = 13,
|
||||
SyncSendDelete = 14,
|
||||
|
||||
AuthRequest = 15,
|
||||
AuthRequestResponse = 16,
|
||||
|
||||
None = 100,
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue