| 
						
						
						
					 | 
					@ -1,7 +1,6 @@ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					use std::collections::{HashMap, HashSet}; | 
					 | 
					 | 
					use std::collections::{HashMap, HashSet}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					use chrono::{NaiveDateTime, Utc}; | 
					 | 
					 | 
					use chrono::{NaiveDateTime, Utc}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					use futures::{stream, stream::StreamExt}; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					use rocket::fs::TempFile; | 
					 | 
					 | 
					use rocket::fs::TempFile; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					use rocket::serde::json::Json; | 
					 | 
					 | 
					use rocket::serde::json::Json; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					use rocket::{ | 
					 | 
					 | 
					use rocket::{ | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -85,8 +84,8 @@ pub fn routes() -> Vec<Route> { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					pub async fn purge_trashed_ciphers(pool: DbPool) { | 
					 | 
					 | 
					pub async fn purge_trashed_ciphers(pool: DbPool) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    debug!("Purging trashed ciphers"); | 
					 | 
					 | 
					    debug!("Purging trashed ciphers"); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    if let Ok(conn) = pool.get().await { | 
					 | 
					 | 
					    if let Ok(mut conn) = pool.get().await { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        Cipher::purge_trash(&conn).await; | 
					 | 
					 | 
					        Cipher::purge_trash(&mut conn).await; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    } else { | 
					 | 
					 | 
					    } else { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        error!("Failed to get DB connection while purging trashed ciphers") | 
					 | 
					 | 
					        error!("Failed to get DB connection while purging trashed ciphers") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -99,39 +98,33 @@ struct SyncData { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[get("/sync?<data..>")] | 
					 | 
					 | 
					#[get("/sync?<data..>")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn sync(data: SyncData, headers: Headers, conn: DbConn) -> Json<Value> { | 
					 | 
					 | 
					async fn sync(data: SyncData, headers: Headers, mut conn: DbConn) -> Json<Value> { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let user_json = headers.user.to_json(&conn).await; | 
					 | 
					 | 
					    let user_json = headers.user.to_json(&mut conn).await; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // 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, &mut conn).await; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, CipherSyncType::User, &conn).await; | 
					 | 
					 | 
					    let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, CipherSyncType::User, &mut 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 mut ciphers_json = Vec::new(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        .then(|c| async { | 
					 | 
					 | 
					    for c in ciphers { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            let c = c; // Move out this single variable
 | 
					 | 
					 | 
					        ciphers_json.push(c.to_json(&headers.host, &headers.user.uuid, Some(&cipher_sync_data), &mut conn).await); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            c.to_json(&headers.host, &headers.user.uuid, Some(&cipher_sync_data), &conn).await | 
					 | 
					 | 
					    } | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        }) | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        .collect() | 
					 | 
					 | 
					    let mut collections_json = Vec::new(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        .await; | 
					 | 
					 | 
					    for c in Collection::find_by_user_uuid(headers.user.uuid.clone(), &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					
 | 
					 | 
					 | 
					        collections_json.push(c.to_json_details(&headers.user.uuid, Some(&cipher_sync_data), &mut conn).await); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let collections_json: Vec<Value> = stream::iter(Collection::find_by_user_uuid(&headers.user.uuid, &conn).await) | 
					 | 
					 | 
					    } | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					        .then(|c| async { | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            let c = c; // Move out this single variable
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            c.to_json_details(&headers.user.uuid, Some(&cipher_sync_data), &conn).await | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        }) | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        .collect() | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        .await; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let folders_json: Vec<Value> = | 
					 | 
					 | 
					    let folders_json: Vec<Value> = | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        Folder::find_by_user(&headers.user.uuid, &conn).await.iter().map(Folder::to_json).collect(); | 
					 | 
					 | 
					        Folder::find_by_user(&headers.user.uuid, &mut conn).await.iter().map(Folder::to_json).collect(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let sends_json: Vec<Value> = | 
					 | 
					 | 
					    let sends_json: Vec<Value> = | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        Send::find_by_user(&headers.user.uuid, &conn).await.iter().map(Send::to_json).collect(); | 
					 | 
					 | 
					        Send::find_by_user(&headers.user.uuid, &mut conn).await.iter().map(Send::to_json).collect(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let policies_json: Vec<Value> = | 
					 | 
					 | 
					    let policies_json: Vec<Value> = | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        OrgPolicy::find_confirmed_by_user(&headers.user.uuid, &conn).await.iter().map(OrgPolicy::to_json).collect(); | 
					 | 
					 | 
					        OrgPolicy::find_confirmed_by_user(&headers.user.uuid, &mut conn).await.iter().map(OrgPolicy::to_json).collect(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let domains_json = if data.exclude_domains { | 
					 | 
					 | 
					    let domains_json = if data.exclude_domains { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Value::Null | 
					 | 
					 | 
					        Value::Null | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -153,17 +146,14 @@ 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, mut 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, &mut conn).await; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, CipherSyncType::User, &conn).await; | 
					 | 
					 | 
					    let cipher_sync_data = CipherSyncData::new(&headers.user.uuid, &ciphers, CipherSyncType::User, &mut conn).await; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let ciphers_json = stream::iter(ciphers) | 
					 | 
					 | 
					    let mut ciphers_json = Vec::new(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        .then(|c| async { | 
					 | 
					 | 
					    for c in ciphers { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            let c = c; // Move out this single variable
 | 
					 | 
					 | 
					        ciphers_json.push(c.to_json(&headers.host, &headers.user.uuid, Some(&cipher_sync_data), &mut conn).await); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            c.to_json(&headers.host, &headers.user.uuid, Some(&cipher_sync_data), &conn).await | 
					 | 
					 | 
					    } | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					        }) | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        .collect::<Vec<Value>>() | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        .await; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    Json(json!({ | 
					 | 
					 | 
					    Json(json!({ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					      "Data": ciphers_json, | 
					 | 
					 | 
					      "Data": ciphers_json, | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -173,17 +163,17 @@ async fn get_ciphers(headers: Headers, conn: DbConn) -> Json<Value> { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[get("/ciphers/<uuid>")] | 
					 | 
					 | 
					#[get("/ciphers/<uuid>")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn get_cipher(uuid: String, headers: Headers, conn: DbConn) -> JsonResult { | 
					 | 
					 | 
					async fn get_cipher(uuid: String, headers: Headers, mut conn: DbConn) -> JsonResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let cipher = match Cipher::find_by_uuid(&uuid, &conn).await { | 
					 | 
					 | 
					    let cipher = match Cipher::find_by_uuid(&uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        Some(cipher) => cipher, | 
					 | 
					 | 
					        Some(cipher) => cipher, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }; | 
					 | 
					 | 
					    }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    if !cipher.is_accessible_to_user(&headers.user.uuid, &conn).await { | 
					 | 
					 | 
					    if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        err!("Cipher is not owned by user") | 
					 | 
					 | 
					        err!("Cipher is not owned by user") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &conn).await)) | 
					 | 
					 | 
					    Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &mut conn).await)) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[get("/ciphers/<uuid>/admin")] | 
					 | 
					 | 
					#[get("/ciphers/<uuid>/admin")] | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -269,7 +259,7 @@ async fn post_ciphers_admin( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					async fn post_ciphers_create( | 
					 | 
					 | 
					async fn post_ciphers_create( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<ShareCipherData>, | 
					 | 
					 | 
					    data: JsonUpcase<ShareCipherData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> JsonResult { | 
					 | 
					 | 
					) -> JsonResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let mut data: ShareCipherData = data.into_inner().data; | 
					 | 
					 | 
					    let mut data: ShareCipherData = data.into_inner().data; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -283,11 +273,11 @@ async fn post_ciphers_create( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // This check is usually only needed in update_cipher_from_data(), but we
 | 
					 | 
					 | 
					    // This check is usually only needed in update_cipher_from_data(), but we
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // need it here as well to avoid creating an empty cipher in the call to
 | 
					 | 
					 | 
					    // need it here as well to avoid creating an empty cipher in the call to
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // cipher.save() below.
 | 
					 | 
					 | 
					    // cipher.save() below.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    enforce_personal_ownership_policy(Some(&data.Cipher), &headers, &conn).await?; | 
					 | 
					 | 
					    enforce_personal_ownership_policy(Some(&data.Cipher), &headers, &mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let mut cipher = Cipher::new(data.Cipher.Type, data.Cipher.Name.clone()); | 
					 | 
					 | 
					    let mut cipher = Cipher::new(data.Cipher.Type, data.Cipher.Name.clone()); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    cipher.user_uuid = Some(headers.user.uuid.clone()); | 
					 | 
					 | 
					    cipher.user_uuid = Some(headers.user.uuid.clone()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    cipher.save(&conn).await?; | 
					 | 
					 | 
					    cipher.save(&mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // When cloning a cipher, the Bitwarden clients seem to set this field
 | 
					 | 
					 | 
					    // When cloning a cipher, the Bitwarden clients seem to set this field
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // based on the cipher being cloned (when creating a new cipher, it's set
 | 
					 | 
					 | 
					    // based on the cipher being cloned (when creating a new cipher, it's set
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -297,12 +287,12 @@ async fn post_ciphers_create( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // or otherwise), we can just ignore this field entirely.
 | 
					 | 
					 | 
					    // or otherwise), we can just ignore this field entirely.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data.Cipher.LastKnownRevisionDate = None; | 
					 | 
					 | 
					    data.Cipher.LastKnownRevisionDate = None; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    share_cipher_by_uuid(&cipher.uuid, data, &headers, &conn, &nt).await | 
					 | 
					 | 
					    share_cipher_by_uuid(&cipher.uuid, data, &headers, &mut conn, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					/// Called when creating a new user-owned cipher.
 | 
					 | 
					 | 
					/// Called when creating a new user-owned cipher.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[post("/ciphers", data = "<data>")] | 
					 | 
					 | 
					#[post("/ciphers", data = "<data>")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn post_ciphers(data: JsonUpcase<CipherData>, headers: Headers, conn: DbConn, nt: Notify<'_>) -> JsonResult { | 
					 | 
					 | 
					async fn post_ciphers(data: JsonUpcase<CipherData>, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    let mut data: CipherData = data.into_inner().data; | 
					 | 
					 | 
					    let mut data: CipherData = data.into_inner().data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // The web/browser clients set this field to null as expected, but the
 | 
					 | 
					 | 
					    // The web/browser clients set this field to null as expected, but the
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -312,9 +302,9 @@ async fn post_ciphers(data: JsonUpcase<CipherData>, headers: Headers, conn: DbCo | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data.LastKnownRevisionDate = None; | 
					 | 
					 | 
					    data.LastKnownRevisionDate = None; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let mut cipher = Cipher::new(data.Type, data.Name.clone()); | 
					 | 
					 | 
					    let mut cipher = Cipher::new(data.Type, data.Name.clone()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    update_cipher_from_data(&mut cipher, data, &headers, false, &conn, &nt, UpdateType::CipherCreate).await?; | 
					 | 
					 | 
					    update_cipher_from_data(&mut cipher, data, &headers, false, &mut conn, &nt, UpdateType::CipherCreate).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &conn).await)) | 
					 | 
					 | 
					    Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &mut conn).await)) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					/// Enforces the personal ownership policy on user-owned ciphers, if applicable.
 | 
					 | 
					 | 
					/// Enforces the personal ownership policy on user-owned ciphers, if applicable.
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -324,7 +314,11 @@ async fn post_ciphers(data: JsonUpcase<CipherData>, headers: Headers, conn: DbCo | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					/// allowed to delete or share such ciphers to an org, however.
 | 
					 | 
					 | 
					/// allowed to delete or share such ciphers to an org, however.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					///
 | 
					 | 
					 | 
					///
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					/// Ref: https://bitwarden.com/help/article/policies/#personal-ownership
 | 
					 | 
					 | 
					/// Ref: https://bitwarden.com/help/article/policies/#personal-ownership
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn enforce_personal_ownership_policy(data: Option<&CipherData>, headers: &Headers, conn: &DbConn) -> EmptyResult { | 
					 | 
					 | 
					async fn enforce_personal_ownership_policy( | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    data: Option<&CipherData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    headers: &Headers, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					    conn: &mut DbConn, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if data.is_none() || data.unwrap().OrganizationId.is_none() { | 
					 | 
					 | 
					    if data.is_none() || data.unwrap().OrganizationId.is_none() { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        let user_uuid = &headers.user.uuid; | 
					 | 
					 | 
					        let user_uuid = &headers.user.uuid; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        let policy_type = OrgPolicyType::PersonalOwnership; | 
					 | 
					 | 
					        let policy_type = OrgPolicyType::PersonalOwnership; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -340,7 +334,7 @@ pub async fn update_cipher_from_data( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: CipherData, | 
					 | 
					 | 
					    data: CipherData, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: &Headers, | 
					 | 
					 | 
					    headers: &Headers, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    shared_to_collection: bool, | 
					 | 
					 | 
					    shared_to_collection: bool, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: &DbConn, | 
					 | 
					 | 
					    conn: &mut DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: &Notify<'_>, | 
					 | 
					 | 
					    nt: &Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    ut: UpdateType, | 
					 | 
					 | 
					    ut: UpdateType, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -493,10 +487,10 @@ struct RelationsData { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					async fn post_ciphers_import( | 
					 | 
					 | 
					async fn post_ciphers_import( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<ImportData>, | 
					 | 
					 | 
					    data: JsonUpcase<ImportData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    enforce_personal_ownership_policy(None, &headers, &conn).await?; | 
					 | 
					 | 
					    enforce_personal_ownership_policy(None, &headers, &mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let data: ImportData = data.into_inner().data; | 
					 | 
					 | 
					    let data: ImportData = data.into_inner().data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -504,7 +498,7 @@ async fn post_ciphers_import( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let mut folders: Vec<_> = Vec::new(); | 
					 | 
					 | 
					    let mut folders: Vec<_> = Vec::new(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for folder in data.Folders.into_iter() { | 
					 | 
					 | 
					    for folder in data.Folders.into_iter() { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        let mut new_folder = Folder::new(headers.user.uuid.clone(), folder.Name); | 
					 | 
					 | 
					        let mut new_folder = Folder::new(headers.user.uuid.clone(), folder.Name); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        new_folder.save(&conn).await?; | 
					 | 
					 | 
					        new_folder.save(&mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        folders.push(new_folder); | 
					 | 
					 | 
					        folders.push(new_folder); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -522,11 +516,11 @@ async fn post_ciphers_import( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        cipher_data.FolderId = folder_uuid; | 
					 | 
					 | 
					        cipher_data.FolderId = folder_uuid; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        let mut cipher = Cipher::new(cipher_data.Type, cipher_data.Name.clone()); | 
					 | 
					 | 
					        let mut cipher = Cipher::new(cipher_data.Type, cipher_data.Name.clone()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        update_cipher_from_data(&mut cipher, cipher_data, &headers, false, &conn, &nt, UpdateType::None).await?; | 
					 | 
					 | 
					        update_cipher_from_data(&mut cipher, cipher_data, &headers, false, &mut conn, &nt, UpdateType::None).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let mut user = headers.user; | 
					 | 
					 | 
					    let mut user = headers.user; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    user.update_revision(&conn).await?; | 
					 | 
					 | 
					    user.update_revision(&mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt.send_user_update(UpdateType::Vault, &user).await; | 
					 | 
					 | 
					    nt.send_user_update(UpdateType::Vault, &user).await; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    Ok(()) | 
					 | 
					 | 
					    Ok(()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -570,12 +564,12 @@ async fn put_cipher( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: String, | 
					 | 
					 | 
					    uuid: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<CipherData>, | 
					 | 
					 | 
					    data: JsonUpcase<CipherData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> JsonResult { | 
					 | 
					 | 
					) -> JsonResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let data: CipherData = data.into_inner().data; | 
					 | 
					 | 
					    let data: CipherData = data.into_inner().data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let mut cipher = match Cipher::find_by_uuid(&uuid, &conn).await { | 
					 | 
					 | 
					    let mut cipher = match Cipher::find_by_uuid(&uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        Some(cipher) => cipher, | 
					 | 
					 | 
					        Some(cipher) => cipher, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }; | 
					 | 
					 | 
					    }; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -585,13 +579,13 @@ async fn put_cipher( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // cipher itself, so the user shouldn't need write access to change these.
 | 
					 | 
					 | 
					    // cipher itself, so the user shouldn't need write access to change these.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // Interestingly, upstream Bitwarden doesn't properly handle this either.
 | 
					 | 
					 | 
					    // Interestingly, upstream Bitwarden doesn't properly handle this either.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    if !cipher.is_write_accessible_to_user(&headers.user.uuid, &conn).await { | 
					 | 
					 | 
					    if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        err!("Cipher is not write accessible") | 
					 | 
					 | 
					        err!("Cipher is not write accessible") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    update_cipher_from_data(&mut cipher, data, &headers, false, &conn, &nt, UpdateType::CipherUpdate).await?; | 
					 | 
					 | 
					    update_cipher_from_data(&mut cipher, data, &headers, false, &mut conn, &nt, UpdateType::CipherUpdate).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &conn).await)) | 
					 | 
					 | 
					    Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &mut conn).await)) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[derive(Deserialize)] | 
					 | 
					 | 
					#[derive(Deserialize)] | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -635,34 +629,34 @@ async fn post_collections_admin( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: String, | 
					 | 
					 | 
					    uuid: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<CollectionsAdminData>, | 
					 | 
					 | 
					    data: JsonUpcase<CollectionsAdminData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let data: CollectionsAdminData = data.into_inner().data; | 
					 | 
					 | 
					    let data: CollectionsAdminData = data.into_inner().data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let cipher = match Cipher::find_by_uuid(&uuid, &conn).await { | 
					 | 
					 | 
					    let cipher = match Cipher::find_by_uuid(&uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        Some(cipher) => cipher, | 
					 | 
					 | 
					        Some(cipher) => cipher, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }; | 
					 | 
					 | 
					    }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    if !cipher.is_write_accessible_to_user(&headers.user.uuid, &conn).await { | 
					 | 
					 | 
					    if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        err!("Cipher is not write accessible") | 
					 | 
					 | 
					        err!("Cipher is not write accessible") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let posted_collections: HashSet<String> = data.CollectionIds.iter().cloned().collect(); | 
					 | 
					 | 
					    let posted_collections: HashSet<String> = data.CollectionIds.iter().cloned().collect(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let current_collections: HashSet<String> = | 
					 | 
					 | 
					    let current_collections: HashSet<String> = | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        cipher.get_collections(&headers.user.uuid, &conn).await.iter().cloned().collect(); | 
					 | 
					 | 
					        cipher.get_collections(headers.user.uuid.clone(), &mut conn).await.iter().cloned().collect(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for collection in posted_collections.symmetric_difference(¤t_collections) { | 
					 | 
					 | 
					    for collection in posted_collections.symmetric_difference(¤t_collections) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        match Collection::find_by_uuid(collection, &conn).await { | 
					 | 
					 | 
					        match Collection::find_by_uuid(collection, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            None => err!("Invalid collection ID provided"), | 
					 | 
					 | 
					            None => err!("Invalid collection ID provided"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Some(collection) => { | 
					 | 
					 | 
					            Some(collection) => { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                if collection.is_writable_by_user(&headers.user.uuid, &conn).await { | 
					 | 
					 | 
					                if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                    if posted_collections.contains(&collection.uuid) { | 
					 | 
					 | 
					                    if posted_collections.contains(&collection.uuid) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        // Add to collection
 | 
					 | 
					 | 
					                        // Add to collection
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        CollectionCipher::save(&cipher.uuid, &collection.uuid, &conn).await?; | 
					 | 
					 | 
					                        CollectionCipher::save(&cipher.uuid, &collection.uuid, &mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                    } else { | 
					 | 
					 | 
					                    } else { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        // Remove from collection
 | 
					 | 
					 | 
					                        // Remove from collection
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        CollectionCipher::delete(&cipher.uuid, &collection.uuid, &conn).await?; | 
					 | 
					 | 
					                        CollectionCipher::delete(&cipher.uuid, &collection.uuid, &mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                    } | 
					 | 
					 | 
					                    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                } else { | 
					 | 
					 | 
					                } else { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    err!("No rights to modify the collection") | 
					 | 
					 | 
					                    err!("No rights to modify the collection") | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -686,12 +680,12 @@ async fn post_cipher_share( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: String, | 
					 | 
					 | 
					    uuid: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<ShareCipherData>, | 
					 | 
					 | 
					    data: JsonUpcase<ShareCipherData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> JsonResult { | 
					 | 
					 | 
					) -> JsonResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let data: ShareCipherData = data.into_inner().data; | 
					 | 
					 | 
					    let data: ShareCipherData = data.into_inner().data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    share_cipher_by_uuid(&uuid, data, &headers, &conn, &nt).await | 
					 | 
					 | 
					    share_cipher_by_uuid(&uuid, data, &headers, &mut conn, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[put("/ciphers/<uuid>/share", data = "<data>")] | 
					 | 
					 | 
					#[put("/ciphers/<uuid>/share", data = "<data>")] | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -699,12 +693,12 @@ async fn put_cipher_share( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: String, | 
					 | 
					 | 
					    uuid: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<ShareCipherData>, | 
					 | 
					 | 
					    data: JsonUpcase<ShareCipherData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> JsonResult { | 
					 | 
					 | 
					) -> JsonResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let data: ShareCipherData = data.into_inner().data; | 
					 | 
					 | 
					    let data: ShareCipherData = data.into_inner().data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    share_cipher_by_uuid(&uuid, data, &headers, &conn, &nt).await | 
					 | 
					 | 
					    share_cipher_by_uuid(&uuid, data, &headers, &mut conn, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[derive(Deserialize)] | 
					 | 
					 | 
					#[derive(Deserialize)] | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -718,7 +712,7 @@ struct ShareSelectedCipherData { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					async fn put_cipher_share_selected( | 
					 | 
					 | 
					async fn put_cipher_share_selected( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<ShareSelectedCipherData>, | 
					 | 
					 | 
					    data: JsonUpcase<ShareSelectedCipherData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let mut data: ShareSelectedCipherData = data.into_inner().data; | 
					 | 
					 | 
					    let mut data: ShareSelectedCipherData = data.into_inner().data; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -746,7 +740,7 @@ async fn put_cipher_share_selected( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        }; | 
					 | 
					 | 
					        }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        match shared_cipher_data.Cipher.Id.take() { | 
					 | 
					 | 
					        match shared_cipher_data.Cipher.Id.take() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            Some(id) => share_cipher_by_uuid(&id, shared_cipher_data, &headers, &conn, &nt).await?, | 
					 | 
					 | 
					            Some(id) => share_cipher_by_uuid(&id, shared_cipher_data, &headers, &mut conn, &nt).await?, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            None => err!("Request missing ids field"), | 
					 | 
					 | 
					            None => err!("Request missing ids field"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        }; | 
					 | 
					 | 
					        }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -758,7 +752,7 @@ async fn share_cipher_by_uuid( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: &str, | 
					 | 
					 | 
					    uuid: &str, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: ShareCipherData, | 
					 | 
					 | 
					    data: ShareCipherData, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: &Headers, | 
					 | 
					 | 
					    headers: &Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: &DbConn, | 
					 | 
					 | 
					    conn: &mut DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: &Notify<'_>, | 
					 | 
					 | 
					    nt: &Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> JsonResult { | 
					 | 
					 | 
					) -> JsonResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let mut cipher = match Cipher::find_by_uuid(uuid, conn).await { | 
					 | 
					 | 
					    let mut cipher = match Cipher::find_by_uuid(uuid, conn).await { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -816,8 +810,8 @@ async fn share_cipher_by_uuid( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					/// their object storage service. For self-hosted instances, it basically just
 | 
					 | 
					 | 
					/// their object storage service. For self-hosted instances, it basically just
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					/// redirects to the same location as before the v2 API.
 | 
					 | 
					 | 
					/// redirects to the same location as before the v2 API.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[get("/ciphers/<uuid>/attachment/<attachment_id>")] | 
					 | 
					 | 
					#[get("/ciphers/<uuid>/attachment/<attachment_id>")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn get_attachment(uuid: String, attachment_id: String, headers: Headers, conn: DbConn) -> JsonResult { | 
					 | 
					 | 
					async fn get_attachment(uuid: String, attachment_id: String, headers: Headers, mut conn: DbConn) -> JsonResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    match Attachment::find_by_id(&attachment_id, &conn).await { | 
					 | 
					 | 
					    match Attachment::find_by_id(&attachment_id, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        Some(attachment) if uuid == attachment.cipher_uuid => Ok(Json(attachment.to_json(&headers.host))), | 
					 | 
					 | 
					        Some(attachment) if uuid == attachment.cipher_uuid => Ok(Json(attachment.to_json(&headers.host))), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Some(_) => err!("Attachment doesn't belong to cipher"), | 
					 | 
					 | 
					        Some(_) => err!("Attachment doesn't belong to cipher"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        None => err!("Attachment doesn't exist"), | 
					 | 
					 | 
					        None => err!("Attachment doesn't exist"), | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -847,14 +841,14 @@ async fn post_attachment_v2( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: String, | 
					 | 
					 | 
					    uuid: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<AttachmentRequestData>, | 
					 | 
					 | 
					    data: JsonUpcase<AttachmentRequestData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					) -> JsonResult { | 
					 | 
					 | 
					) -> JsonResult { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let cipher = match Cipher::find_by_uuid(&uuid, &conn).await { | 
					 | 
					 | 
					    let cipher = match Cipher::find_by_uuid(&uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        Some(cipher) => cipher, | 
					 | 
					 | 
					        Some(cipher) => cipher, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }; | 
					 | 
					 | 
					    }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    if !cipher.is_write_accessible_to_user(&headers.user.uuid, &conn).await { | 
					 | 
					 | 
					    if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        err!("Cipher is not write accessible") | 
					 | 
					 | 
					        err!("Cipher is not write accessible") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -862,7 +856,7 @@ async fn post_attachment_v2( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let data: AttachmentRequestData = data.into_inner().data; | 
					 | 
					 | 
					    let data: AttachmentRequestData = data.into_inner().data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let attachment = | 
					 | 
					 | 
					    let attachment = | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Attachment::new(attachment_id.clone(), cipher.uuid.clone(), data.FileName, data.FileSize, Some(data.Key)); | 
					 | 
					 | 
					        Attachment::new(attachment_id.clone(), cipher.uuid.clone(), data.FileName, data.FileSize, Some(data.Key)); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    attachment.save(&conn).await.expect("Error saving attachment"); | 
					 | 
					 | 
					    attachment.save(&mut conn).await.expect("Error saving attachment"); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let url = format!("/ciphers/{}/attachment/{}", cipher.uuid, attachment_id); | 
					 | 
					 | 
					    let url = format!("/ciphers/{}/attachment/{}", cipher.uuid, attachment_id); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let response_key = match data.AdminRequest { | 
					 | 
					 | 
					    let response_key = match data.AdminRequest { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -875,7 +869,7 @@ async fn post_attachment_v2( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        "AttachmentId": attachment_id, | 
					 | 
					 | 
					        "AttachmentId": attachment_id, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        "Url": url, | 
					 | 
					 | 
					        "Url": url, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        "FileUploadType": FileUploadType::Direct as i32, | 
					 | 
					 | 
					        "FileUploadType": FileUploadType::Direct as i32, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        response_key: cipher.to_json(&headers.host, &headers.user.uuid, None, &conn).await, | 
					 | 
					 | 
					        response_key: cipher.to_json(&headers.host, &headers.user.uuid, None, &mut conn).await, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    }))) | 
					 | 
					 | 
					    }))) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -898,15 +892,15 @@ async fn save_attachment( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    cipher_uuid: String, | 
					 | 
					 | 
					    cipher_uuid: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: Form<UploadData<'_>>, | 
					 | 
					 | 
					    data: Form<UploadData<'_>>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: &Headers, | 
					 | 
					 | 
					    headers: &Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> Result<(Cipher, DbConn), crate::error::Error> { | 
					 | 
					 | 
					) -> Result<(Cipher, DbConn), crate::error::Error> { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let cipher = match Cipher::find_by_uuid(&cipher_uuid, &conn).await { | 
					 | 
					 | 
					    let cipher = match Cipher::find_by_uuid(&cipher_uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        Some(cipher) => cipher, | 
					 | 
					 | 
					        Some(cipher) => cipher, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }; | 
					 | 
					 | 
					    }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    if !cipher.is_write_accessible_to_user(&headers.user.uuid, &conn).await { | 
					 | 
					 | 
					    if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        err!("Cipher is not write accessible") | 
					 | 
					 | 
					        err!("Cipher is not write accessible") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -921,7 +915,7 @@ async fn save_attachment( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        match CONFIG.user_attachment_limit() { | 
					 | 
					 | 
					        match CONFIG.user_attachment_limit() { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Some(0) => err!("Attachments are disabled"), | 
					 | 
					 | 
					            Some(0) => err!("Attachments are disabled"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Some(limit_kb) => { | 
					 | 
					 | 
					            Some(limit_kb) => { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                let left = (limit_kb * 1024) - Attachment::size_by_user(user_uuid, &conn).await + size_adjust; | 
					 | 
					 | 
					                let left = (limit_kb * 1024) - Attachment::size_by_user(user_uuid, &mut conn).await + size_adjust; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                if left <= 0 { | 
					 | 
					 | 
					                if left <= 0 { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    err!("Attachment storage limit reached! Delete some attachments to free up space") | 
					 | 
					 | 
					                    err!("Attachment storage limit reached! Delete some attachments to free up space") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                } | 
					 | 
					 | 
					                } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -933,7 +927,7 @@ async fn save_attachment( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        match CONFIG.org_attachment_limit() { | 
					 | 
					 | 
					        match CONFIG.org_attachment_limit() { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Some(0) => err!("Attachments are disabled"), | 
					 | 
					 | 
					            Some(0) => err!("Attachments are disabled"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Some(limit_kb) => { | 
					 | 
					 | 
					            Some(limit_kb) => { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                let left = (limit_kb * 1024) - Attachment::size_by_org(org_uuid, &conn).await + size_adjust; | 
					 | 
					 | 
					                let left = (limit_kb * 1024) - Attachment::size_by_org(org_uuid, &mut conn).await + size_adjust; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                if left <= 0 { | 
					 | 
					 | 
					                if left <= 0 { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    err!("Attachment storage limit reached! Delete some attachments to free up space") | 
					 | 
					 | 
					                    err!("Attachment storage limit reached! Delete some attachments to free up space") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                } | 
					 | 
					 | 
					                } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -990,10 +984,10 @@ async fn save_attachment( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            if size != attachment.file_size { | 
					 | 
					 | 
					            if size != attachment.file_size { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                // Update the attachment with the actual file size.
 | 
					 | 
					 | 
					                // Update the attachment with the actual file size.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                attachment.file_size = size; | 
					 | 
					 | 
					                attachment.file_size = size; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                attachment.save(&conn).await.expect("Error updating attachment"); | 
					 | 
					 | 
					                attachment.save(&mut conn).await.expect("Error updating attachment"); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } else { | 
					 | 
					 | 
					        } else { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            attachment.delete(&conn).await.ok(); | 
					 | 
					 | 
					            attachment.delete(&mut conn).await.ok(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            err!(format!("Attachment size mismatch (expected within [{}, {}], got {})", min_size, max_size, size)); | 
					 | 
					 | 
					            err!(format!("Attachment size mismatch (expected within [{}, {}], got {})", min_size, max_size, size)); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1008,14 +1002,14 @@ async fn save_attachment( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            err!("No attachment key provided") | 
					 | 
					 | 
					            err!("No attachment key provided") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        let attachment = Attachment::new(file_id, cipher_uuid.clone(), encrypted_filename.unwrap(), size, data.key); | 
					 | 
					 | 
					        let attachment = Attachment::new(file_id, cipher_uuid.clone(), encrypted_filename.unwrap(), size, data.key); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        attachment.save(&conn).await.expect("Error saving attachment"); | 
					 | 
					 | 
					        attachment.save(&mut conn).await.expect("Error saving attachment"); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if let Err(_err) = data.data.persist_to(&file_path).await { | 
					 | 
					 | 
					    if let Err(_err) = data.data.persist_to(&file_path).await { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        data.data.move_copy_to(file_path).await? | 
					 | 
					 | 
					        data.data.move_copy_to(file_path).await? | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &cipher.update_users_revision(&conn).await).await; | 
					 | 
					 | 
					    nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &cipher.update_users_revision(&mut conn).await).await; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    Ok((cipher, conn)) | 
					 | 
					 | 
					    Ok((cipher, conn)) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1030,10 +1024,10 @@ async fn post_attachment_v2_data( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    attachment_id: String, | 
					 | 
					 | 
					    attachment_id: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: Form<UploadData<'_>>, | 
					 | 
					 | 
					    data: Form<UploadData<'_>>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let attachment = match Attachment::find_by_id(&attachment_id, &conn).await { | 
					 | 
					 | 
					    let attachment = match Attachment::find_by_id(&attachment_id, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        Some(attachment) if uuid == attachment.cipher_uuid => Some(attachment), | 
					 | 
					 | 
					        Some(attachment) if uuid == attachment.cipher_uuid => Some(attachment), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Some(_) => err!("Attachment doesn't belong to cipher"), | 
					 | 
					 | 
					        Some(_) => err!("Attachment doesn't belong to cipher"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        None => err!("Attachment doesn't exist"), | 
					 | 
					 | 
					        None => err!("Attachment doesn't exist"), | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1057,9 +1051,9 @@ async fn post_attachment( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // the attachment database record as well as saving the data to disk.
 | 
					 | 
					 | 
					    // the attachment database record as well as saving the data to disk.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let attachment = None; | 
					 | 
					 | 
					    let attachment = None; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let (cipher, conn) = save_attachment(attachment, uuid, data, &headers, conn, nt).await?; | 
					 | 
					 | 
					    let (cipher, mut conn) = save_attachment(attachment, uuid, data, &headers, conn, nt).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &conn).await)) | 
					 | 
					 | 
					    Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, None, &mut conn).await)) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[post("/ciphers/<uuid>/attachment-admin", format = "multipart/form-data", data = "<data>")] | 
					 | 
					 | 
					#[post("/ciphers/<uuid>/attachment-admin", format = "multipart/form-data", data = "<data>")] | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1079,10 +1073,10 @@ async fn post_attachment_share( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    attachment_id: String, | 
					 | 
					 | 
					    attachment_id: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: Form<UploadData<'_>>, | 
					 | 
					 | 
					    data: Form<UploadData<'_>>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> JsonResult { | 
					 | 
					 | 
					) -> JsonResult { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &conn, &nt).await?; | 
					 | 
					 | 
					    _delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &mut conn, &nt).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    post_attachment(uuid, data, headers, conn, nt).await | 
					 | 
					 | 
					    post_attachment(uuid, data, headers, conn, nt).await | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -1113,10 +1107,10 @@ async fn delete_attachment( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: String, | 
					 | 
					 | 
					    uuid: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    attachment_id: String, | 
					 | 
					 | 
					    attachment_id: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &conn, &nt).await | 
					 | 
					 | 
					    _delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &mut conn, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[delete("/ciphers/<uuid>/attachment/<attachment_id>/admin")] | 
					 | 
					 | 
					#[delete("/ciphers/<uuid>/attachment/<attachment_id>/admin")] | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1124,40 +1118,40 @@ async fn delete_attachment_admin( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: String, | 
					 | 
					 | 
					    uuid: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    attachment_id: String, | 
					 | 
					 | 
					    attachment_id: String, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &conn, &nt).await | 
					 | 
					 | 
					    _delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &mut conn, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[post("/ciphers/<uuid>/delete")] | 
					 | 
					 | 
					#[post("/ciphers/<uuid>/delete")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn delete_cipher_post(uuid: String, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
					 | 
					 | 
					async fn delete_cipher_post(uuid: String, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &conn, false, &nt).await | 
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &mut conn, false, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[post("/ciphers/<uuid>/delete-admin")] | 
					 | 
					 | 
					#[post("/ciphers/<uuid>/delete-admin")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn delete_cipher_post_admin(uuid: String, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
					 | 
					 | 
					async fn delete_cipher_post_admin(uuid: String, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &conn, false, &nt).await | 
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &mut conn, false, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[put("/ciphers/<uuid>/delete")] | 
					 | 
					 | 
					#[put("/ciphers/<uuid>/delete")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn delete_cipher_put(uuid: String, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
					 | 
					 | 
					async fn delete_cipher_put(uuid: String, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &conn, true, &nt).await | 
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &mut conn, true, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[put("/ciphers/<uuid>/delete-admin")] | 
					 | 
					 | 
					#[put("/ciphers/<uuid>/delete-admin")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn delete_cipher_put_admin(uuid: String, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
					 | 
					 | 
					async fn delete_cipher_put_admin(uuid: String, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &conn, true, &nt).await | 
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &mut conn, true, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[delete("/ciphers/<uuid>")] | 
					 | 
					 | 
					#[delete("/ciphers/<uuid>")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn delete_cipher(uuid: String, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
					 | 
					 | 
					async fn delete_cipher(uuid: String, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &conn, false, &nt).await | 
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &mut conn, false, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[delete("/ciphers/<uuid>/admin")] | 
					 | 
					 | 
					#[delete("/ciphers/<uuid>/admin")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn delete_cipher_admin(uuid: String, headers: Headers, conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
					 | 
					 | 
					async fn delete_cipher_admin(uuid: String, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &conn, false, &nt).await | 
					 | 
					 | 
					    _delete_cipher_by_uuid(&uuid, &headers, &mut conn, false, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[delete("/ciphers", data = "<data>")] | 
					 | 
					 | 
					#[delete("/ciphers", data = "<data>")] | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -1221,23 +1215,23 @@ async fn delete_cipher_selected_put_admin( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[put("/ciphers/<uuid>/restore")] | 
					 | 
					 | 
					#[put("/ciphers/<uuid>/restore")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn restore_cipher_put(uuid: String, headers: Headers, conn: DbConn, nt: Notify<'_>) -> JsonResult { | 
					 | 
					 | 
					async fn restore_cipher_put(uuid: String, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _restore_cipher_by_uuid(&uuid, &headers, &conn, &nt).await | 
					 | 
					 | 
					    _restore_cipher_by_uuid(&uuid, &headers, &mut conn, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[put("/ciphers/<uuid>/restore-admin")] | 
					 | 
					 | 
					#[put("/ciphers/<uuid>/restore-admin")] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn restore_cipher_put_admin(uuid: String, headers: Headers, conn: DbConn, nt: Notify<'_>) -> JsonResult { | 
					 | 
					 | 
					async fn restore_cipher_put_admin(uuid: String, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _restore_cipher_by_uuid(&uuid, &headers, &conn, &nt).await | 
					 | 
					 | 
					    _restore_cipher_by_uuid(&uuid, &headers, &mut conn, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[put("/ciphers/restore", data = "<data>")] | 
					 | 
					 | 
					#[put("/ciphers/restore", data = "<data>")] | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					async fn restore_cipher_selected( | 
					 | 
					 | 
					async fn restore_cipher_selected( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<Value>, | 
					 | 
					 | 
					    data: JsonUpcase<Value>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> JsonResult { | 
					 | 
					 | 
					) -> JsonResult { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    _restore_multiple_ciphers(data, &headers, &conn, &nt).await | 
					 | 
					 | 
					    _restore_multiple_ciphers(data, &headers, &mut conn, &nt).await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#[derive(Deserialize)] | 
					 | 
					 | 
					#[derive(Deserialize)] | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1251,14 +1245,14 @@ struct MoveCipherData { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					async fn move_cipher_selected( | 
					 | 
					 | 
					async fn move_cipher_selected( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<MoveCipherData>, | 
					 | 
					 | 
					    data: JsonUpcase<MoveCipherData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let data = data.into_inner().data; | 
					 | 
					 | 
					    let data = data.into_inner().data; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let user_uuid = headers.user.uuid; | 
					 | 
					 | 
					    let user_uuid = headers.user.uuid; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    if let Some(ref folder_id) = data.FolderId { | 
					 | 
					 | 
					    if let Some(ref folder_id) = data.FolderId { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        match Folder::find_by_uuid(folder_id, &conn).await { | 
					 | 
					 | 
					        match Folder::find_by_uuid(folder_id, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            Some(folder) => { | 
					 | 
					 | 
					            Some(folder) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                if folder.user_uuid != user_uuid { | 
					 | 
					 | 
					                if folder.user_uuid != user_uuid { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    err!("Folder is not owned by user") | 
					 | 
					 | 
					                    err!("Folder is not owned by user") | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1269,17 +1263,17 @@ async fn move_cipher_selected( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for uuid in data.Ids { | 
					 | 
					 | 
					    for uuid in data.Ids { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        let cipher = match Cipher::find_by_uuid(&uuid, &conn).await { | 
					 | 
					 | 
					        let cipher = match Cipher::find_by_uuid(&uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            Some(cipher) => cipher, | 
					 | 
					 | 
					            Some(cipher) => cipher, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            None => err!("Cipher doesn't exist"), | 
					 | 
					 | 
					            None => err!("Cipher doesn't exist"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        }; | 
					 | 
					 | 
					        }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        if !cipher.is_accessible_to_user(&user_uuid, &conn).await { | 
					 | 
					 | 
					        if !cipher.is_accessible_to_user(&user_uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            err!("Cipher is not accessible by user") | 
					 | 
					 | 
					            err!("Cipher is not accessible by user") | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        // Move cipher
 | 
					 | 
					 | 
					        // Move cipher
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        cipher.move_to_folder(data.FolderId.clone(), &user_uuid, &conn).await?; | 
					 | 
					 | 
					        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::CipherUpdate, &cipher, &[user_uuid.clone()]).await; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -1308,7 +1302,7 @@ async fn delete_all( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    organization: Option<OrganizationId>, | 
					 | 
					 | 
					    organization: Option<OrganizationId>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<PasswordData>, | 
					 | 
					 | 
					    data: JsonUpcase<PasswordData>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let data: PasswordData = data.into_inner().data; | 
					 | 
					 | 
					    let data: PasswordData = data.into_inner().data; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1323,11 +1317,11 @@ async fn delete_all( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    match organization { | 
					 | 
					 | 
					    match organization { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Some(org_data) => { | 
					 | 
					 | 
					        Some(org_data) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // Organization ID in query params, purging organization vault
 | 
					 | 
					 | 
					            // Organization ID in query params, purging organization vault
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            match UserOrganization::find_by_user_and_org(&user.uuid, &org_data.org_id, &conn).await { | 
					 | 
					 | 
					            match UserOrganization::find_by_user_and_org(&user.uuid, &org_data.org_id, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					                None => err!("You don't have permission to purge the organization vault"), | 
					 | 
					 | 
					                None => err!("You don't have permission to purge the organization vault"), | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                Some(user_org) => { | 
					 | 
					 | 
					                Some(user_org) => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    if user_org.atype == UserOrgType::Owner { | 
					 | 
					 | 
					                    if user_org.atype == UserOrgType::Owner { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                        Cipher::delete_all_by_organization(&org_data.org_id, &conn).await?; | 
					 | 
					 | 
					                        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::Vault, &user).await; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                        Ok(()) | 
					 | 
					 | 
					                        Ok(()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                    } else { | 
					 | 
					 | 
					                    } else { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1339,16 +1333,16 @@ async fn delete_all( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        None => { | 
					 | 
					 | 
					        None => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // No organization ID in query params, purging user vault
 | 
					 | 
					 | 
					            // No organization ID in query params, purging user vault
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // Delete ciphers and their attachments
 | 
					 | 
					 | 
					            // Delete ciphers and their attachments
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            for cipher in Cipher::find_owned_by_user(&user.uuid, &conn).await { | 
					 | 
					 | 
					            for cipher in Cipher::find_owned_by_user(&user.uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					                cipher.delete(&conn).await?; | 
					 | 
					 | 
					                cipher.delete(&mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // Delete folders
 | 
					 | 
					 | 
					            // Delete folders
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            for f in Folder::find_by_user(&user.uuid, &conn).await { | 
					 | 
					 | 
					            for f in Folder::find_by_user(&user.uuid, &mut conn).await { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					                f.delete(&conn).await?; | 
					 | 
					 | 
					                f.delete(&mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            user.update_revision(&conn).await?; | 
					 | 
					 | 
					            user.update_revision(&mut conn).await?; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            nt.send_user_update(UpdateType::Vault, &user).await; | 
					 | 
					 | 
					            nt.send_user_update(UpdateType::Vault, &user).await; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Ok(()) | 
					 | 
					 | 
					            Ok(()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1358,7 +1352,7 @@ async fn delete_all( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					async fn _delete_cipher_by_uuid( | 
					 | 
					 | 
					async fn _delete_cipher_by_uuid( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: &str, | 
					 | 
					 | 
					    uuid: &str, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: &Headers, | 
					 | 
					 | 
					    headers: &Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: &DbConn, | 
					 | 
					 | 
					    conn: &mut DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    soft_delete: bool, | 
					 | 
					 | 
					    soft_delete: bool, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    nt: &Notify<'_>, | 
					 | 
					 | 
					    nt: &Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -1386,7 +1380,7 @@ async fn _delete_cipher_by_uuid( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					async fn _delete_multiple_ciphers( | 
					 | 
					 | 
					async fn _delete_multiple_ciphers( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<Value>, | 
					 | 
					 | 
					    data: JsonUpcase<Value>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: Headers, | 
					 | 
					 | 
					    headers: Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: DbConn, | 
					 | 
					 | 
					    mut conn: DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    soft_delete: bool, | 
					 | 
					 | 
					    soft_delete: bool, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    nt: Notify<'_>, | 
					 | 
					 | 
					    nt: Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1401,7 +1395,7 @@ async fn _delete_multiple_ciphers( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }; | 
					 | 
					 | 
					    }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for uuid in uuids { | 
					 | 
					 | 
					    for uuid in uuids { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        if let error @ Err(_) = _delete_cipher_by_uuid(uuid, &headers, &conn, soft_delete, &nt).await { | 
					 | 
					 | 
					        if let error @ Err(_) = _delete_cipher_by_uuid(uuid, &headers, &mut conn, soft_delete, &nt).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            return error; | 
					 | 
					 | 
					            return error; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        }; | 
					 | 
					 | 
					        }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1409,7 +1403,7 @@ async fn _delete_multiple_ciphers( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    Ok(()) | 
					 | 
					 | 
					    Ok(()) | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					async fn _restore_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &DbConn, nt: &Notify<'_>) -> JsonResult { | 
					 | 
					 | 
					async fn _restore_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &mut DbConn, nt: &Notify<'_>) -> JsonResult { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    let mut cipher = match Cipher::find_by_uuid(uuid, conn).await { | 
					 | 
					 | 
					    let mut cipher = match Cipher::find_by_uuid(uuid, conn).await { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Some(cipher) => cipher, | 
					 | 
					 | 
					        Some(cipher) => cipher, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
					 | 
					 | 
					        None => err!("Cipher doesn't exist"), | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1429,7 +1423,7 @@ async fn _restore_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &DbConn, n | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					async fn _restore_multiple_ciphers( | 
					 | 
					 | 
					async fn _restore_multiple_ciphers( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    data: JsonUpcase<Value>, | 
					 | 
					 | 
					    data: JsonUpcase<Value>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: &Headers, | 
					 | 
					 | 
					    headers: &Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: &DbConn, | 
					 | 
					 | 
					    conn: &mut DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: &Notify<'_>, | 
					 | 
					 | 
					    nt: &Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> JsonResult { | 
					 | 
					 | 
					) -> JsonResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let data: Value = data.into_inner().data; | 
					 | 
					 | 
					    let data: Value = data.into_inner().data; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -1461,7 +1455,7 @@ async fn _delete_cipher_attachment_by_id( | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    uuid: &str, | 
					 | 
					 | 
					    uuid: &str, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    attachment_id: &str, | 
					 | 
					 | 
					    attachment_id: &str, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    headers: &Headers, | 
					 | 
					 | 
					    headers: &Headers, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    conn: &DbConn, | 
					 | 
					 | 
					    conn: &mut DbConn, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					    nt: &Notify<'_>, | 
					 | 
					 | 
					    nt: &Notify<'_>, | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					) -> EmptyResult { | 
					 | 
					 | 
					) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let attachment = match Attachment::find_by_id(attachment_id, conn).await { | 
					 | 
					 | 
					    let attachment = match Attachment::find_by_id(attachment_id, conn).await { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -1509,9 +1503,9 @@ pub enum CipherSyncType { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					impl CipherSyncData { | 
					 | 
					 | 
					impl CipherSyncData { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    pub async fn new(user_uuid: &str, ciphers: &Vec<Cipher>, sync_type: CipherSyncType, conn: &DbConn) -> Self { | 
					 | 
					 | 
					    pub async fn new(user_uuid: &str, ciphers: &[Cipher], sync_type: CipherSyncType, conn: &mut 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.clone()).collect::<Vec<String>>().await; | 
					 | 
					 | 
					        let cipher_uuids = ciphers.iter().map(|c| c.uuid.clone()).collect(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        let mut cipher_folders: HashMap<String, String> = HashMap::new(); | 
					 | 
					 | 
					        let mut cipher_folders: HashMap<String, String> = HashMap::new(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        let mut cipher_favorites: HashSet<String> = HashSet::new(); | 
					 | 
					 | 
					        let mut cipher_favorites: HashSet<String> = HashSet::new(); | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1519,11 +1513,10 @@ impl CipherSyncData { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // User Sync supports Folders and Favorits
 | 
					 | 
					 | 
					            // User Sync supports Folders and Favorits
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            CipherSyncType::User => { | 
					 | 
					 | 
					            CipherSyncType::User => { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                // Generate a HashMap with the Cipher UUID as key and the Folder UUID as value
 | 
					 | 
					 | 
					                // 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; | 
					 | 
					 | 
					                cipher_folders = FolderCipher::find_by_user(user_uuid, conn).await.into_iter().collect(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                // Generate a HashSet of all the Cipher UUID's which are marked as favorite
 | 
					 | 
					 | 
					                // Generate a HashSet of all the Cipher UUID's which are marked as favorite
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                cipher_favorites = | 
					 | 
					 | 
					                cipher_favorites = Favorite::get_all_cipher_uuid_by_user(user_uuid, conn).await.into_iter().collect(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					                    stream::iter(Favorite::get_all_cipher_uuid_by_user(user_uuid, conn).await).collect().await; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // Organization Sync does not support Folders and Favorits.
 | 
					 | 
					 | 
					            // Organization Sync does not support Folders and Favorits.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // If these are set, it will cause issues in the web-vault.
 | 
					 | 
					 | 
					            // If these are set, it will cause issues in the web-vault.
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -1538,33 +1531,34 @@ impl CipherSyncData { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        // 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.to_string(), conn).await { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            cipher_collections.entry(cipher).or_default().push(collection); | 
					 | 
					 | 
					            cipher_collections.entry(cipher).or_default().push(collection); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        // Generate a HashMap with the Organization UUID as key and the UserOrganization record
 | 
					 | 
					 | 
					        // Generate a HashMap with the Organization UUID as key and the UserOrganization record
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        let user_organizations: HashMap<String, UserOrganization> = | 
					 | 
					 | 
					        let user_organizations: HashMap<String, UserOrganization> = UserOrganization::find_by_user(user_uuid, conn) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            stream::iter(UserOrganization::find_by_user(user_uuid, conn).await) | 
					 | 
					 | 
					            .await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            .into_iter() | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            .map(|uo| (uo.org_uuid.clone(), uo)) | 
					 | 
					 | 
					            .map(|uo| (uo.org_uuid.clone(), uo)) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                .collect() | 
					 | 
					 | 
					            .collect(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					                .await; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        // Generate a HashMap with the User_Collections UUID as key and the CollectionUser record
 | 
					 | 
					 | 
					        // Generate a HashMap with the User_Collections UUID as key and the CollectionUser record
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        let user_collections: HashMap<String, CollectionUser> = | 
					 | 
					 | 
					        let user_collections: HashMap<String, CollectionUser> = CollectionUser::find_by_user(user_uuid, conn) | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					            stream::iter(CollectionUser::find_by_user(user_uuid, conn).await) | 
					 | 
					 | 
					            .await | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            .into_iter() | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            .map(|uc| (uc.collection_uuid.clone(), uc)) | 
					 | 
					 | 
					            .map(|uc| (uc.collection_uuid.clone(), uc)) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					                .collect() | 
					 | 
					 | 
					            .collect(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					                .await; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        // Generate a HashMap with the collections_uuid as key and the CollectionGroup record
 | 
					 | 
					 | 
					        // Generate a HashMap with the collections_uuid as key and the CollectionGroup record
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        let user_collections_groups = stream::iter(CollectionGroup::find_by_user(user_uuid, conn).await) | 
					 | 
					 | 
					        let user_collections_groups = CollectionGroup::find_by_user(user_uuid, conn) | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            .await | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					 | 
					 | 
					 | 
					            .into_iter() | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            .map(|collection_group| (collection_group.collections_uuid.clone(), collection_group)) | 
					 | 
					 | 
					            .map(|collection_group| (collection_group.collections_uuid.clone(), collection_group)) | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            .collect() | 
					 | 
					 | 
					            .collect(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					            .await; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        // Get all organizations that the user has full access to via group assignement
 | 
					 | 
					 | 
					        // Get all organizations that the user has full access to via group assignement
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        let user_group_full_access_for_organizations = | 
					 | 
					 | 
					        let user_group_full_access_for_organizations = | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            stream::iter(Group::gather_user_organizations_full_access(user_uuid, conn).await).collect().await; | 
					 | 
					 | 
					            Group::gather_user_organizations_full_access(user_uuid, conn).await.into_iter().collect(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Self { | 
					 | 
					 | 
					        Self { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            cipher_attachments, | 
					 | 
					 | 
					            cipher_attachments, | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					
  |