From b71d9dd53e447eb66786d0890fb4b595210de158 Mon Sep 17 00:00:00 2001 From: BlackDex Date: Tue, 21 Jun 2022 17:36:07 +0200 Subject: [PATCH] Fix for issue #2566 This PR fixes #2566 If Organizational syncs returned a FolderId it would cause the web-vault to hide the cipher because there is a FolderId set. Upstream seems to not return FolderId and Favorite. When set to null/false it will behave the same. In this PR I have added a new CipherSyncType enum to select which type of sync to execute, and return an empty list for both Folders and Favorites if this is for Orgs. This also reduces the database load a bit since it will not execute those queries. --- src/api/core/ciphers.rs | 36 ++++++++++++++++++++++---------- src/api/core/emergency_access.rs | 8 +++++-- src/api/core/mod.rs | 2 +- src/api/core/organizations.rs | 6 +++--- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index 71417097..d70dd906 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -104,7 +104,7 @@ async fn sync(data: SyncData, headers: Headers, conn: DbConn) -> Json { // Get all ciphers which are visible by the user let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn).await; - let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, &conn).await; + let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, CipherSyncType::User, &conn).await; // Lets generate the ciphers_json using all the gathered info let ciphers_json: Vec = stream::iter(ciphers) @@ -154,7 +154,7 @@ async fn sync(data: SyncData, headers: Headers, conn: DbConn) -> Json { #[get("/ciphers")] async fn get_ciphers(headers: Headers, conn: DbConn) -> Json { let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn).await; - let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, &conn).await; + let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, CipherSyncType::User, &conn).await; let ciphers_json = stream::iter(ciphers) .then(|c| async { @@ -1486,25 +1486,39 @@ pub struct CipherSyncData { pub user_collections: HashMap, } +pub enum CipherSyncType { + User, + Organization, +} + impl CipherSyncData { - pub async fn new(user_uuid: &str, ciphers: &Vec, conn: &DbConn) -> Self { + pub async fn new(user_uuid: &str, ciphers: &Vec, sync_type: CipherSyncType, conn: &DbConn) -> Self { // Generate a list of Cipher UUID's to be used during a query filter with an eq_any. let cipher_uuids = stream::iter(ciphers).map(|c| c.uuid.to_string()).collect::>().await; + let mut cipher_folders: HashMap = HashMap::new(); + let mut cipher_favorites: HashSet = HashSet::new(); + match sync_type { + // User Sync supports Folders and Favorits + CipherSyncType::User => { + // Generate a HashMap with the Cipher UUID as key and the Folder UUID as value + cipher_folders = stream::iter(FolderCipher::find_by_user(user_uuid, conn).await).collect().await; + + // Generate a HashSet of all the Cipher UUID's which are marked as favorite + cipher_favorites = + stream::iter(Favorite::get_all_cipher_uuid_by_user(user_uuid, conn).await).collect().await; + } + // Organization Sync does not support Folders and Favorits. + // If these are set, it will cause issues in the web-vault. + CipherSyncType::Organization => {} + } + // Generate a list of Cipher UUID's containing a Vec with one or more Attachment records let mut cipher_attachments: HashMap> = HashMap::new(); for attachment in Attachment::find_all_by_ciphers(&cipher_uuids, conn).await { cipher_attachments.entry(attachment.cipher_uuid.to_string()).or_default().push(attachment); } - // Generate a HashMap with the Cipher UUID as key and the Folder UUID as value - let cipher_folders: HashMap = - stream::iter(FolderCipher::find_by_user(user_uuid, conn).await).collect().await; - - // Generate a HashSet of all the Cipher UUID's which are marked as favorite - let cipher_favorites: HashSet = - stream::iter(Favorite::get_all_cipher_uuid_by_user(user_uuid, conn).await).collect().await; - // Generate a HashMap with the Cipher UUID as key and one or more Collection UUID's let mut cipher_collections: HashMap> = HashMap::new(); for (cipher, collection) in Cipher::get_collections_with_cipher_by_user(user_uuid, conn).await { diff --git a/src/api/core/emergency_access.rs b/src/api/core/emergency_access.rs index 7ca501cb..74197020 100644 --- a/src/api/core/emergency_access.rs +++ b/src/api/core/emergency_access.rs @@ -5,7 +5,10 @@ use serde_json::Value; use std::borrow::Borrow; use crate::{ - api::{core::CipherSyncData, EmptyResult, JsonResult, JsonUpcase, NumberOrString}, + api::{ + core::{CipherSyncData, CipherSyncType}, + EmptyResult, JsonResult, JsonUpcase, NumberOrString, + }, auth::{decode_emergency_access_invite, Headers}, db::{models::*, DbConn, DbPool}, mail, CONFIG, @@ -596,7 +599,8 @@ async fn view_emergency_access(emer_id: String, headers: Headers, conn: DbConn) } let ciphers = Cipher::find_owned_by_user(&emergency_access.grantor_uuid, &conn).await; - let cipher_sync_data = CipherSyncData::new(&emergency_access.grantor_uuid, &ciphers, &conn).await; + let cipher_sync_data = + CipherSyncData::new(&emergency_access.grantor_uuid, &ciphers, CipherSyncType::User, &conn).await; let ciphers_json = stream::iter(ciphers) .then(|c| async { diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs index 3a6208dd..c54ebeb7 100644 --- a/src/api/core/mod.rs +++ b/src/api/core/mod.rs @@ -7,7 +7,7 @@ mod sends; pub mod two_factor; pub use ciphers::purge_trashed_ciphers; -pub use ciphers::CipherSyncData; +pub use ciphers::{CipherSyncData, CipherSyncType}; pub use emergency_access::{emergency_notification_reminder_job, emergency_request_timeout_job}; pub use sends::purge_sends; pub use two_factor::send_incomplete_2fa_notifications; diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index c4ae909c..7064f221 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -5,8 +5,8 @@ use serde_json::Value; use crate::{ api::{ - core::CipherSyncData, EmptyResult, JsonResult, JsonUpcase, JsonUpcaseVec, Notify, NumberOrString, PasswordData, - UpdateType, + core::{CipherSyncData, CipherSyncType}, + EmptyResult, JsonResult, JsonUpcase, JsonUpcaseVec, Notify, NumberOrString, PasswordData, UpdateType, }, auth::{decode_invite, AdminHeaders, Headers, ManagerHeaders, ManagerHeadersLoose, OwnerHeaders}, db::{models::*, DbConn}, @@ -487,7 +487,7 @@ struct OrgIdData { #[get("/ciphers/organization-details?")] async fn get_org_details(data: OrgIdData, headers: Headers, conn: DbConn) -> Json { let ciphers = Cipher::find_by_org(&data.organization_id, &conn).await; - let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, &conn).await; + let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, CipherSyncType::Organization, &conn).await; let ciphers_json = stream::iter(ciphers) .then(|c| async {