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.
This commit is contained in:
BlackDex 2022-06-21 17:36:07 +02:00
parent 887e320e7f
commit b71d9dd53e
No known key found for this signature in database
GPG key ID: 58C80A2AA6C765E1
4 changed files with 35 additions and 17 deletions

View file

@ -104,7 +104,7 @@ async fn sync(data: SyncData, headers: Headers, conn: DbConn) -> Json<Value> {
// Get all ciphers which are visible by the user // Get all ciphers which are visible by the user
let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn).await; 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 // Lets generate the ciphers_json using all the gathered info
let ciphers_json: Vec<Value> = stream::iter(ciphers) let ciphers_json: Vec<Value> = stream::iter(ciphers)
@ -154,7 +154,7 @@ async fn sync(data: SyncData, headers: Headers, conn: DbConn) -> Json<Value> {
#[get("/ciphers")] #[get("/ciphers")]
async fn get_ciphers(headers: Headers, conn: DbConn) -> Json<Value> { async fn get_ciphers(headers: Headers, conn: DbConn) -> Json<Value> {
let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn).await; 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) let ciphers_json = stream::iter(ciphers)
.then(|c| async { .then(|c| async {
@ -1486,25 +1486,39 @@ pub struct CipherSyncData {
pub user_collections: HashMap<String, CollectionUser>, pub user_collections: HashMap<String, CollectionUser>,
} }
pub enum CipherSyncType {
User,
Organization,
}
impl CipherSyncData { impl CipherSyncData {
pub async fn new(user_uuid: &str, ciphers: &Vec<Cipher>, conn: &DbConn) -> Self { pub async fn new(user_uuid: &str, ciphers: &Vec<Cipher>, sync_type: CipherSyncType, conn: &DbConn) -> Self {
// Generate a list of Cipher UUID's to be used during a query filter with an eq_any. // 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::<Vec<String>>().await; let cipher_uuids = stream::iter(ciphers).map(|c| c.uuid.to_string()).collect::<Vec<String>>().await;
let mut cipher_folders: HashMap<String, String> = HashMap::new();
let mut cipher_favorites: HashSet<String> = 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 // Generate a list of Cipher UUID's containing a Vec with one or more Attachment records
let mut cipher_attachments: HashMap<String, Vec<Attachment>> = HashMap::new(); let mut cipher_attachments: HashMap<String, Vec<Attachment>> = HashMap::new();
for attachment in Attachment::find_all_by_ciphers(&cipher_uuids, conn).await { for attachment in Attachment::find_all_by_ciphers(&cipher_uuids, conn).await {
cipher_attachments.entry(attachment.cipher_uuid.to_string()).or_default().push(attachment); 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<String, String> =
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<String> =
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 // Generate a HashMap with the Cipher UUID as key and one or more Collection UUID's
let mut cipher_collections: HashMap<String, Vec<String>> = HashMap::new(); let mut cipher_collections: HashMap<String, Vec<String>> = HashMap::new();
for (cipher, collection) in Cipher::get_collections_with_cipher_by_user(user_uuid, conn).await { for (cipher, collection) in Cipher::get_collections_with_cipher_by_user(user_uuid, conn).await {

View file

@ -5,7 +5,10 @@ use serde_json::Value;
use std::borrow::Borrow; use std::borrow::Borrow;
use crate::{ use crate::{
api::{core::CipherSyncData, EmptyResult, JsonResult, JsonUpcase, NumberOrString}, api::{
core::{CipherSyncData, CipherSyncType},
EmptyResult, JsonResult, JsonUpcase, NumberOrString,
},
auth::{decode_emergency_access_invite, Headers}, auth::{decode_emergency_access_invite, Headers},
db::{models::*, DbConn, DbPool}, db::{models::*, DbConn, DbPool},
mail, CONFIG, 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 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) let ciphers_json = stream::iter(ciphers)
.then(|c| async { .then(|c| async {

View file

@ -7,7 +7,7 @@ mod sends;
pub mod two_factor; pub mod two_factor;
pub use ciphers::purge_trashed_ciphers; 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 emergency_access::{emergency_notification_reminder_job, emergency_request_timeout_job};
pub use sends::purge_sends; pub use sends::purge_sends;
pub use two_factor::send_incomplete_2fa_notifications; pub use two_factor::send_incomplete_2fa_notifications;

View file

@ -5,8 +5,8 @@ use serde_json::Value;
use crate::{ use crate::{
api::{ api::{
core::CipherSyncData, EmptyResult, JsonResult, JsonUpcase, JsonUpcaseVec, Notify, NumberOrString, PasswordData, core::{CipherSyncData, CipherSyncType},
UpdateType, EmptyResult, JsonResult, JsonUpcase, JsonUpcaseVec, Notify, NumberOrString, PasswordData, UpdateType,
}, },
auth::{decode_invite, AdminHeaders, Headers, ManagerHeaders, ManagerHeadersLoose, OwnerHeaders}, auth::{decode_invite, AdminHeaders, Headers, ManagerHeaders, ManagerHeadersLoose, OwnerHeaders},
db::{models::*, DbConn}, db::{models::*, DbConn},
@ -487,7 +487,7 @@ struct OrgIdData {
#[get("/ciphers/organization-details?<data..>")] #[get("/ciphers/organization-details?<data..>")]
async fn get_org_details(data: OrgIdData, headers: Headers, conn: DbConn) -> Json<Value> { async fn get_org_details(data: OrgIdData, headers: Headers, conn: DbConn) -> Json<Value> {
let ciphers = Cipher::find_by_org(&data.organization_id, &conn).await; 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) let ciphers_json = stream::iter(ciphers)
.then(|c| async { .then(|c| async {