@ -12,7 +12,7 @@ use serde_json::Value; 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					use   crate ::util ::NumberOrString ;  
			
		
	
		
			
				
					use   crate ::{  
			
		
	
		
			
				
					     api ::{ self ,   core ::log_event ,   EmptyResult ,   JsonResult ,   JsonUpcase ,   Notify ,   PasswordOrOtpData ,   UpdateType } ,  
			
		
	
		
			
				
					     api ::{ self ,   core ::log_event ,   EmptyResult ,   JsonResult ,   Notify ,   PasswordOrOtpData ,   UpdateType } ,  
			
		
	
		
			
				
					     auth ::Headers ,  
			
		
	
		
			
				
					     crypto ,  
			
		
	
		
			
				
					     db ::{ models ::* ,   DbConn ,   DbPool } ,  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -141,15 +141,15 @@ async fn sync(data: SyncData, headers: Headers, mut conn: DbConn) -> Json<Value> 
			
		
	
		
			
				
					     } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     Json ( json ! ( {  
			
		
	
		
			
				
					         "P rofile" : user_json ,  
			
		
	
		
			
				
					         "F olders" : folders_json ,  
			
		
	
		
			
				
					         "C ollections" : collections_json ,  
			
		
	
		
			
				
					         "P olicies" : policies_json ,  
			
		
	
		
			
				
					         "C iphers" : ciphers_json ,  
			
		
	
		
			
				
					         "D omains" : domains_json ,  
			
		
	
		
			
				
					         "S ends" : sends_json ,  
			
		
	
		
			
				
					         "p rofile" : user_json ,  
			
		
	
		
			
				
					         "f olders" : folders_json ,  
			
		
	
		
			
				
					         "c ollections" : collections_json ,  
			
		
	
		
			
				
					         "p olicies" : policies_json ,  
			
		
	
		
			
				
					         "c iphers" : ciphers_json ,  
			
		
	
		
			
				
					         "d omains" : domains_json ,  
			
		
	
		
			
				
					         "s ends" : sends_json ,  
			
		
	
		
			
				
					         "unofficialServer" : true ,  
			
		
	
		
			
				
					         "O bject" : "sync"  
			
		
	
		
			
				
					         "o bject" : "sync"  
			
		
	
		
			
				
					     } ) )  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -167,9 +167,9 @@ async fn get_ciphers(headers: Headers, mut conn: DbConn) -> Json<Value> { 
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     Json ( json ! ( {  
			
		
	
		
			
				
					       "D ata" : ciphers_json ,  
			
		
	
		
			
				
					       "O bject" : "list" ,  
			
		
	
		
			
				
					       "C ontinuationToken" : null  
			
		
	
		
			
				
					       "d ata" : ciphers_json ,  
			
		
	
		
			
				
					       "o bject" : "list" ,  
			
		
	
		
			
				
					       "c ontinuationToken" : null  
			
		
	
		
			
				
					     } ) )  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -198,17 +198,17 @@ async fn get_cipher_details(uuid: &str, headers: Headers, conn: DbConn) -> JsonR 
			
		
	
		
			
				
					     get_cipher ( uuid ,   headers ,   conn ) . await  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize, Debug ) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ derive(Debug, De serialize) ]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					pub   struct  CipherData   {  
			
		
	
		
			
				
					     // Id is optional as it is included only in bulk share
  
			
		
	
		
			
				
					     pub   I dOption < String > ,  
			
		
	
		
			
				
					     pub   i dOption < String > ,  
			
		
	
		
			
				
					     // Folder id is not included in import
  
			
		
	
		
			
				
					     FolderI dOption < String > ,  
			
		
	
		
			
				
					     folder_i dOption < String > ,  
			
		
	
		
			
				
					     // TODO: Some of these might appear all the time, no need for Option
  
			
		
	
		
			
				
					     pub   OrganizationI dOption < String > ,  
			
		
	
		
			
				
					     pub   organization_i dOption < String > ,  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     K eyOption < String > ,  
			
		
	
		
			
				
					     k eyOption < String > ,  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     /*  
			
		
	
		
			
				
					     Login   =   1 ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -216,27 +216,27 @@ pub struct CipherData { 
			
		
	
		
			
				
					     Card   =   3 ,  
			
		
	
		
			
				
					     Identity   =   4  
			
		
	
		
			
				
					     * /  
			
		
	
		
			
				
					     pub   T ypei32 ,  
			
		
	
		
			
				
					     pub   N ameString ,  
			
		
	
		
			
				
					     pub   N otesOption < String > ,  
			
		
	
		
			
				
					     F ieldsOption < Value > ,  
			
		
	
		
			
				
					     pub   r#t ypei32 ,  
			
		
	
		
			
				
					     pub   n ameString ,  
			
		
	
		
			
				
					     pub   n otesOption < String > ,  
			
		
	
		
			
				
					     f ieldsOption < Value > ,  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // Only one of these should exist, depending on type
  
			
		
	
		
			
				
					     L oginOption < Value > ,  
			
		
	
		
			
				
					     SecureN oteOption < Value > ,  
			
		
	
		
			
				
					     C ardOption < Value > ,  
			
		
	
		
			
				
					     I dentityOption < Value > ,  
			
		
	
		
			
				
					     l oginOption < Value > ,  
			
		
	
		
			
				
					     secure_n oteOption < Value > ,  
			
		
	
		
			
				
					     c ardOption < Value > ,  
			
		
	
		
			
				
					     i dentityOption < Value > ,  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     F avoriteOption < bool > ,  
			
		
	
		
			
				
					     R epromptOption < i32 > ,  
			
		
	
		
			
				
					     f avoriteOption < bool > ,  
			
		
	
		
			
				
					     r epromptOption < i32 > ,  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     PasswordH istoryOption < Value > ,  
			
		
	
		
			
				
					     password_h istoryOption < Value > ,  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // These are used during key rotation
  
			
		
	
		
			
				
					     // 'Attachments' is unused, contains map of {id: filename}
  
			
		
	
		
			
				
					     #[ serde(rename =  " Attachments " ) ]  
			
		
	
		
			
				
					     _A ttachmentsOption < Value > ,  
			
		
	
		
			
				
					     A ttachments2Option < HashMap < String ,   Attachments2Data > > ,  
			
		
	
		
			
				
					     #[ allow(dead_code )]  
			
		
	
		
			
				
					     a ttachmentsOption < Value > ,  
			
		
	
		
			
				
					     a ttachments2Option < HashMap < String ,   Attachments2Data > > ,  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // The revision datetime (in ISO 8601 format) of the client's local copy
  
			
		
	
		
			
				
					     // of the cipher. This is used to prevent a client from updating a cipher
  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -244,31 +244,26 @@ pub struct CipherData { 
			
		
	
		
			
				
					     // loss. It's not an error when no value is provided; this can happen
  
			
		
	
		
			
				
					     // when using older client versions, or if the operation doesn't involve
  
			
		
	
		
			
				
					     // updating an existing cipher.
  
			
		
	
		
			
				
					     LastKnownRevisionD ateOption < String > ,  
			
		
	
		
			
				
					     last_known_revision_d ateOption < String > ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize, Debug ) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ derive(Debug, De serialize) ]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					pub   struct  PartialCipherData   {  
			
		
	
		
			
				
					     FolderI dOption < String > ,  
			
		
	
		
			
				
					     F avoritebool ,  
			
		
	
		
			
				
					     folder_i dOption < String > ,  
			
		
	
		
			
				
					     f avoritebool ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize, Debug ) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ derive(Debug, De serialize) ]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					pub   struct  Attachments2Data   {  
			
		
	
		
			
				
					     FileN ameString ,  
			
		
	
		
			
				
					     K eyString ,  
			
		
	
		
			
				
					     file_n ameString ,  
			
		
	
		
			
				
					     k eyString ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					/// Called when an org admin clones an org cipher.
  
			
		
	
		
			
				
					#[ post( " /ciphers/admin " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_ciphers_admin (  
			
		
	
		
			
				
					     data : JsonUpcase < ShareCipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					async   fn  post_ciphers_admin ( data : Json < ShareCipherData > ,   headers : Headers ,   conn : DbConn ,   nt : Notify < '_ > )   -> JsonResult   {  
			
		
	
		
			
				
					     post_ciphers_create ( data ,   headers ,   conn ,   nt ) . await  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -277,25 +272,25 @@ async fn post_ciphers_admin( 
			
		
	
		
			
				
					/// `organizationId` is null.
  
			
		
	
		
			
				
					#[ post( " /ciphers/create " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_ciphers_create (  
			
		
	
		
			
				
					     data : JsonUpcase  < ShareCipherData > ,  
			
		
	
		
			
				
					     data : Json < ShareCipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					     let   mut   data : ShareCipherData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   mut   data : ShareCipherData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // Check if there are one more more collections selected when this cipher is part of an organization.
  
			
		
	
		
			
				
					     // err if this is not the case before creating an empty cipher.
  
			
		
	
		
			
				
					     if   data . Cipher . OrganizationI d. is_some ( )   & &   data . CollectionI ds. is_empty ( )   {  
			
		
	
		
			
				
					     if   data . cipher . organization_i d. is_some ( )   & &   data . collection_i ds. is_empty ( )   {  
			
		
	
		
			
				
					         err ! ( "You must select at least one collection." ) ;  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // 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
  
			
		
	
		
			
				
					     // cipher.save() below.
  
			
		
	
		
			
				
					     enforce_personal_ownership_policy ( Some ( & data . C ipher) ,   & headers ,   & mut   conn ) . await ? ;  
			
		
	
		
			
				
					     enforce_personal_ownership_policy ( Some ( & data . c ipher) ,   & headers ,   & mut   conn ) . await ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   mut   cipher   =   Cipher ::new ( data . Cipher . T ype,   data . Cipher . N ame. clone ( ) ) ;  
			
		
	
		
			
				
					     let   mut   cipher   =   Cipher ::new ( data . cipher . r#t ype,   data . cipher . n ame. clone ( ) ) ;  
			
		
	
		
			
				
					     cipher . user_uuid   =   Some ( headers . user . uuid . clone ( ) ) ;  
			
		
	
		
			
				
					     cipher . save ( & mut   conn ) . await ? ;  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -305,23 +300,23 @@ async fn post_ciphers_create( 
			
		
	
		
			
				
					     // the current time, so the stale data check will end up failing down the
  
			
		
	
		
			
				
					     // line. Since this function only creates new ciphers (whether by cloning
  
			
		
	
		
			
				
					     // or otherwise), we can just ignore this field entirely.
  
			
		
	
		
			
				
					     data . Cipher . LastKnownRevisionD ate  =   None ;  
			
		
	
		
			
				
					     data . cipher . last_known_revision_d ate  =   None ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     share_cipher_by_uuid ( & cipher . uuid ,   data ,   & headers ,   & mut   conn ,   & nt ) . await  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					/// Called when creating a new user-owned cipher.
  
			
		
	
		
			
				
					#[ post( " /ciphers " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_ciphers ( data : JsonUpcase  < CipherData > ,   headers : Headers ,   mut   conn : DbConn ,   nt : Notify < '_ > )   -> JsonResult   {  
			
		
	
		
			
				
					     let   mut   data : CipherData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					async   fn  post_ciphers ( data : Json < CipherData > ,   headers : Headers ,   mut   conn : DbConn ,   nt : Notify < '_ > )   -> JsonResult   {  
			
		
	
		
			
				
					     let   mut   data : CipherData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // The web/browser clients set this field to null as expected, but the
  
			
		
	
		
			
				
					     // mobile clients seem to set the invalid value `0001-01-01T00:00:00`,
  
			
		
	
		
			
				
					     // which results in a warning message being logged. This field isn't
  
			
		
	
		
			
				
					     // needed when creating a new cipher, so just ignore it unconditionally.
  
			
		
	
		
			
				
					     data . LastKnownRevisionD ate  =   None ;  
			
		
	
		
			
				
					     data . last_known_revision_d ate  =   None ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   mut   cipher   =   Cipher ::new ( data . T ype,   data . N ame. clone ( ) ) ;  
			
		
	
		
			
				
					     let   mut   cipher   =   Cipher ::new ( data . r#t ype,   data . n ame. clone ( ) ) ;  
			
		
	
		
			
				
					     update_cipher_from_data ( & mut   cipher ,   data ,   & headers ,   None ,   & mut   conn ,   & nt ,   UpdateType ::SyncCipherCreate ) . await ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     Ok ( Json ( cipher . to_json ( & headers . host ,   & headers . user . uuid ,   None ,   CipherSyncType ::User ,   & mut   conn ) . await ) )  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -339,7 +334,7 @@ async fn enforce_personal_ownership_policy( 
			
		
	
		
			
				
					     headers : & Headers ,  
			
		
	
		
			
				
					     conn : & mut   DbConn ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					     if   data . is_none ( )   | |   data . unwrap ( ) . OrganizationI d. is_none ( )   {  
			
		
	
		
			
				
					     if   data . is_none ( )   | |   data . unwrap ( ) . organization_i d. is_none ( )   {  
			
		
	
		
			
				
					         let   user_uuid   =   & headers . user . uuid ;  
			
		
	
		
			
				
					         let   policy_type   =   OrgPolicyType ::PersonalOwnership ;  
			
		
	
		
			
				
					         if   OrgPolicy ::is_applicable_to_user ( user_uuid ,   policy_type ,   None ,   conn ) . await   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -363,7 +358,7 @@ pub async fn update_cipher_from_data( 
			
		
	
		
			
				
					     // Check that the client isn't updating an existing cipher with stale data.
  
			
		
	
		
			
				
					     // And only perform this check when not importing ciphers, else the date/time check will fail.
  
			
		
	
		
			
				
					     if   ut   ! =   UpdateType ::None   {  
			
		
	
		
			
				
					         if   let   Some ( dt )   =   data . LastKnownRevisionD ate  {  
			
		
	
		
			
				
					         if   let   Some ( dt )   =   data . last_known_revision_d ate  {  
			
		
	
		
			
				
					             match   NaiveDateTime ::parse_from_str ( & dt ,   "%+" )   {  
			
		
	
		
			
				
					                 // ISO 8601 format
  
			
		
	
		
			
				
					                 Err ( err )   = >   warn ! ( "Error parsing LastKnownRevisionDate '{}': {}" ,   dt ,   err ) ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -375,20 +370,20 @@ pub async fn update_cipher_from_data( 
			
		
	
		
			
				
					         }  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   cipher . organization_uuid . is_some ( )   & &   cipher . organization_uuid   ! =   data . OrganizationI d  {  
			
		
	
		
			
				
					     if   cipher . organization_uuid . is_some ( )   & &   cipher . organization_uuid   ! =   data . organization_i d  {  
			
		
	
		
			
				
					         err ! ( "Organization mismatch. Please resync the client before updating the cipher" )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   let   Some ( note )   =   & data . N otes  {  
			
		
	
		
			
				
					     if   let   Some ( note )   =   & data . n otes  {  
			
		
	
		
			
				
					         if   note . len ( )   >   10_000   {  
			
		
	
		
			
				
					             err ! ( "The field Notes exceeds the maximum encrypted value length of 10000 characters." )  
			
		
	
		
			
				
					         }  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // Check if this cipher is being transferred from a personal to an organization vault
  
			
		
	
		
			
				
					     let   transfer_cipher   =   cipher . organization_uuid . is_none ( )   & &   data . OrganizationI d. is_some ( ) ;  
			
		
	
		
			
				
					     let   transfer_cipher   =   cipher . organization_uuid . is_none ( )   & &   data . organization_i d. is_some ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   let   Some ( org_id )   =   data . OrganizationI d  {  
			
		
	
		
			
				
					     if   let   Some ( org_id )   =   data . organization_i d  {  
			
		
	
		
			
				
					         match   UserOrganization ::find_by_user_and_org ( & headers . user . uuid ,   & org_id ,   conn ) . await   {  
			
		
	
		
			
				
					             None   = >   err ! ( "You don't have permission to add item to organization" ) ,  
			
		
	
		
			
				
					             Some ( org_user )   = >   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -412,7 +407,7 @@ pub async fn update_cipher_from_data( 
			
		
	
		
			
				
					         cipher . user_uuid   =   Some ( headers . user . uuid . clone ( ) ) ;  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   let   Some ( ref   folder_id )   =   data . FolderI d  {  
			
		
	
		
			
				
					     if   let   Some ( ref   folder_id )   =   data . folder_i d  {  
			
		
	
		
			
				
					         match   Folder ::find_by_uuid ( folder_id ,   conn ) . await   {  
			
		
	
		
			
				
					             Some ( folder )   = >   {  
			
		
	
		
			
				
					                 if   folder . user_uuid   ! =   headers . user . uuid   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -424,7 +419,7 @@ pub async fn update_cipher_from_data( 
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // Modify attachments name and keys when rotating
  
			
		
	
		
			
				
					     if   let   Some ( attachments )   =   data . A ttachments2  {  
			
		
	
		
			
				
					     if   let   Some ( attachments )   =   data . a ttachments2  {  
			
		
	
		
			
				
					         for   ( id ,   attachment )   in   attachments   {  
			
		
	
		
			
				
					             let   mut   saved_att   =   match   Attachment ::find_by_id ( & id ,   conn ) . await   {  
			
		
	
		
			
				
					                 Some ( att )   = >   att ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -445,8 +440,8 @@ pub async fn update_cipher_from_data( 
			
		
	
		
			
				
					                 break ;  
			
		
	
		
			
				
					             }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             saved_att . akey   =   Some ( attachment . K ey) ;  
			
		
	
		
			
				
					             saved_att . file_name   =   attachment . FileN ame;  
			
		
	
		
			
				
					             saved_att . akey   =   Some ( attachment . k ey) ;  
			
		
	
		
			
				
					             saved_att . file_name   =   attachment . file_n ame;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             saved_att . save ( conn ) . await ? ;  
			
		
	
		
			
				
					         }  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -460,44 +455,44 @@ pub async fn update_cipher_from_data( 
			
		
	
		
			
				
					     fn  _clean_cipher_data ( mut   json_data : Value )   -> Value   {  
			
		
	
		
			
				
					         if   json_data . is_array ( )   {  
			
		
	
		
			
				
					             json_data . as_array_mut ( ) . unwrap ( ) . iter_mut ( ) . for_each ( | ref   mut   f |   {  
			
		
	
		
			
				
					                 f . as_object_mut ( ) . unwrap ( ) . remove ( "R esponse" ) ;  
			
		
	
		
			
				
					                 f . as_object_mut ( ) . unwrap ( ) . remove ( "r esponse" ) ;  
			
		
	
		
			
				
					             } ) ;  
			
		
	
		
			
				
					         } ;  
			
		
	
		
			
				
					         json_data  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   type_data_opt   =   match   data . T ype  {  
			
		
	
		
			
				
					         1   = >   data . L ogin,  
			
		
	
		
			
				
					         2   = >   data . SecureN ote,  
			
		
	
		
			
				
					         3   = >   data . C ard,  
			
		
	
		
			
				
					         4   = >   data . I dentity,  
			
		
	
		
			
				
					     let   type_data_opt   =   match   data . r#t ype  {  
			
		
	
		
			
				
					         1   = >   data . l ogin,  
			
		
	
		
			
				
					         2   = >   data . secure_n ote,  
			
		
	
		
			
				
					         3   = >   data . c ard,  
			
		
	
		
			
				
					         4   = >   data . i dentity,  
			
		
	
		
			
				
					         _   = >   err ! ( "Invalid type" ) ,  
			
		
	
		
			
				
					     } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   type_data   =   match   type_data_opt   {  
			
		
	
		
			
				
					         Some ( mut   data )   = >   {  
			
		
	
		
			
				
					             // Remove the 'Response' key from the base object.
  
			
		
	
		
			
				
					             data . as_object_mut ( ) . unwrap ( ) . remove ( "R esponse" ) ;  
			
		
	
		
			
				
					             data . as_object_mut ( ) . unwrap ( ) . remove ( "r esponse" ) ;  
			
		
	
		
			
				
					             // Remove the 'Response' key from every Uri.
  
			
		
	
		
			
				
					             if   data [ "U ris" ] . is_array ( )   {  
			
		
	
		
			
				
					                 data [ "U ris" ]   =   _clean_cipher_data ( data [ "U ris" ] . clone ( ) ) ;  
			
		
	
		
			
				
					             if   data [ "u ris" ] . is_array ( )   {  
			
		
	
		
			
				
					                 data [ "u ris" ]   =   _clean_cipher_data ( data [ "u ris" ] . clone ( ) ) ;  
			
		
	
		
			
				
					             }  
			
		
	
		
			
				
					             data  
			
		
	
		
			
				
					         }  
			
		
	
		
			
				
					         None   = >   err ! ( "Data missing" ) ,  
			
		
	
		
			
				
					     } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     cipher . key   =   data . K ey;  
			
		
	
		
			
				
					     cipher . name   =   data . N ame;  
			
		
	
		
			
				
					     cipher . notes   =   data . N otes;  
			
		
	
		
			
				
					     cipher . fields   =   data . F ields. map ( | f |   _clean_cipher_data ( f ) . to_string ( ) ) ;  
			
		
	
		
			
				
					     cipher . key   =   data . k ey;  
			
		
	
		
			
				
					     cipher . name   =   data . n ame;  
			
		
	
		
			
				
					     cipher . notes   =   data . n otes;  
			
		
	
		
			
				
					     cipher . fields   =   data . f ields. map ( | f |   _clean_cipher_data ( f ) . to_string ( ) ) ;  
			
		
	
		
			
				
					     cipher . data   =   type_data . to_string ( ) ;  
			
		
	
		
			
				
					     cipher . password_history   =   data . PasswordH istory. map ( | f |   f . to_string ( ) ) ;  
			
		
	
		
			
				
					     cipher . reprompt   =   data . R eprompt;  
			
		
	
		
			
				
					     cipher . password_history   =   data . password_h istory. map ( | f |   f . to_string ( ) ) ;  
			
		
	
		
			
				
					     cipher . reprompt   =   data . r eprompt;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     cipher . save ( conn ) . await ? ;  
			
		
	
		
			
				
					     cipher . move_to_folder ( data . FolderI d,   & headers . user . uuid ,   conn ) . await ? ;  
			
		
	
		
			
				
					     cipher . set_favorite ( data . F avorite,   & headers . user . uuid ,   conn ) . await ? ;  
			
		
	
		
			
				
					     cipher . move_to_folder ( data . folder_i d,   & headers . user . uuid ,   conn ) . await ? ;  
			
		
	
		
			
				
					     cipher . set_favorite ( data . f avorite,   & headers . user . uuid ,   conn ) . await ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   ut   ! =   UpdateType ::None   {  
			
		
	
		
			
				
					         // Only log events for organizational ciphers
  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -533,43 +528,43 @@ pub async fn update_cipher_from_data( 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					struct  ImportData   {  
			
		
	
		
			
				
					     C iphersVec < CipherData > ,  
			
		
	
		
			
				
					     F oldersVec < FolderData > ,  
			
		
	
		
			
				
					     FolderR elationshipsVec < RelationsData > ,  
			
		
	
		
			
				
					     c iphersVec < CipherData > ,  
			
		
	
		
			
				
					     f oldersVec < FolderData > ,  
			
		
	
		
			
				
					     folder_r elationshipsVec < RelationsData > ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					struct  RelationsData   {  
			
		
	
		
			
				
					     // Cipher id
  
			
		
	
		
			
				
					     K eyusize ,  
			
		
	
		
			
				
					     k eyusize ,  
			
		
	
		
			
				
					     // Folder id
  
			
		
	
		
			
				
					     V alueusize ,  
			
		
	
		
			
				
					     v alueusize ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ post( " /ciphers/import " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_ciphers_import (  
			
		
	
		
			
				
					     data : JsonUpcase  < ImportData > ,  
			
		
	
		
			
				
					     data : Json < ImportData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					     enforce_personal_ownership_policy ( None ,   & headers ,   & mut   conn ) . await ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   data : ImportData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data : ImportData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // Validate the import before continuing
  
			
		
	
		
			
				
					     // Bitwarden does not process the import if there is one item invalid.
  
			
		
	
		
			
				
					     // Since we check for the size of the encrypted note length, we need to do that here to pre-validate it.
  
			
		
	
		
			
				
					     // TODO: See if we can optimize the whole cipher adding/importing and prevent duplicate code and checks.
  
			
		
	
		
			
				
					     Cipher ::validate_notes ( & data . C iphers) ? ;  
			
		
	
		
			
				
					     Cipher ::validate_notes ( & data . c iphers) ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // Read and create the folders
  
			
		
	
		
			
				
					     let   mut   folders : Vec < _ >   =   Vec ::new ( ) ;  
			
		
	
		
			
				
					     for   folder   in   data . F olders. into_iter ( )   {  
			
		
	
		
			
				
					         let   mut   new_folder   =   Folder ::new ( headers . user . uuid . clone ( ) ,   folder . N ame) ;  
			
		
	
		
			
				
					     for   folder   in   data . f olders. into_iter ( )   {  
			
		
	
		
			
				
					         let   mut   new_folder   =   Folder ::new ( headers . user . uuid . clone ( ) ,   folder . n ame) ;  
			
		
	
		
			
				
					         new_folder . save ( & mut   conn ) . await ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         folders . push ( new_folder ) ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -578,16 +573,16 @@ async fn post_ciphers_import( 
			
		
	
		
			
				
					     // Read the relations between folders and ciphers
  
			
		
	
		
			
				
					     let   mut   relations_map   =   HashMap ::new ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     for   relation   in   data . FolderR elationships  {  
			
		
	
		
			
				
					         relations_map . insert ( relation . K ey,   relation . V alue) ;  
			
		
	
		
			
				
					     for   relation   in   data . folder_r elationships  {  
			
		
	
		
			
				
					         relations_map . insert ( relation . k ey,   relation . v alue) ;  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // Read and create the ciphers
  
			
		
	
		
			
				
					     for   ( index ,   mut   cipher_data )   in   data . C iphers. into_iter ( ) . enumerate ( )   {  
			
		
	
		
			
				
					     for   ( index ,   mut   cipher_data )   in   data . c iphers. into_iter ( ) . enumerate ( )   {  
			
		
	
		
			
				
					         let   folder_uuid   =   relations_map . get ( & index ) . map ( | i |   folders [ * i ] . uuid . clone ( ) ) ;  
			
		
	
		
			
				
					         cipher_data . FolderI d  =   folder_uuid ;  
			
		
	
		
			
				
					         cipher_data . folder_i d  =   folder_uuid ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         let   mut   cipher   =   Cipher ::new ( cipher_data . T ype,   cipher_data . N ame. clone ( ) ) ;  
			
		
	
		
			
				
					         let   mut   cipher   =   Cipher ::new ( cipher_data . r#t ype,   cipher_data . n ame. clone ( ) ) ;  
			
		
	
		
			
				
					         update_cipher_from_data ( & mut   cipher ,   cipher_data ,   & headers ,   None ,   & mut   conn ,   & nt ,   UpdateType ::None ) . await ? ;  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -602,7 +597,7 @@ async fn post_ciphers_import( 
			
		
	
		
			
				
					#[ put( " /ciphers/<uuid>/admin " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  put_cipher_admin (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < CipherData > ,  
			
		
	
		
			
				
					     data : Json < CipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -613,7 +608,7 @@ async fn put_cipher_admin( 
			
		
	
		
			
				
					#[ post( " /ciphers/<uuid>/admin " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_cipher_admin (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < CipherData > ,  
			
		
	
		
			
				
					     data : Json < CipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -622,25 +617,19 @@ async fn post_cipher_admin( 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ post( " /ciphers/<uuid> " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_cipher (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase < CipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					async   fn  post_cipher ( uuid : & str ,   data : Json < CipherData > ,   headers : Headers ,   conn : DbConn ,   nt : Notify < '_ > )   -> JsonResult   {  
			
		
	
		
			
				
					     put_cipher ( uuid ,   data ,   headers ,   conn ,   nt ) . await  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ put( " /ciphers/<uuid> " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  put_cipher (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < CipherData > ,  
			
		
	
		
			
				
					     data : Json < CipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					     let   data : CipherData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data : CipherData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   mut   cipher   =   match   Cipher ::find_by_uuid ( uuid ,   & mut   conn ) . await   {  
			
		
	
		
			
				
					         Some ( cipher )   = >   cipher ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -662,12 +651,7 @@ async fn put_cipher( 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ post( " /ciphers/<uuid>/partial " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_cipher_partial (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase < PartialCipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					async   fn  post_cipher_partial ( uuid : & str ,   data : Json < PartialCipherData > ,   headers : Headers ,   conn : DbConn )   -> JsonResult   {  
			
		
	
		
			
				
					     put_cipher_partial ( uuid ,   data ,   headers ,   conn ) . await  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -675,18 +659,18 @@ async fn post_cipher_partial( 
			
		
	
		
			
				
					#[ put( " /ciphers/<uuid>/partial " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  put_cipher_partial (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < PartialCipherData > ,  
			
		
	
		
			
				
					     data : Json < PartialCipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					     let   data : PartialCipherData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data : PartialCipherData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   cipher   =   match   Cipher ::find_by_uuid ( uuid ,   & mut   conn ) . await   {  
			
		
	
		
			
				
					         Some ( cipher )   = >   cipher ,  
			
		
	
		
			
				
					         None   = >   err ! ( "Cipher doesn't exist" ) ,  
			
		
	
		
			
				
					     } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   let   Some ( ref   folder_id )   =   data . FolderI d  {  
			
		
	
		
			
				
					     if   let   Some ( ref   folder_id )   =   data . folder_i d  {  
			
		
	
		
			
				
					         match   Folder ::find_by_uuid ( folder_id ,   & mut   conn ) . await   {  
			
		
	
		
			
				
					             Some ( folder )   = >   {  
			
		
	
		
			
				
					                 if   folder . user_uuid   ! =   headers . user . uuid   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -698,23 +682,23 @@ async fn put_cipher_partial( 
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // Move cipher
  
			
		
	
		
			
				
					     cipher . move_to_folder ( data . FolderI d. clone ( ) ,   & headers . user . uuid ,   & mut   conn ) . await ? ;  
			
		
	
		
			
				
					     cipher . move_to_folder ( data . folder_i d. clone ( ) ,   & headers . user . uuid ,   & mut   conn ) . await ? ;  
			
		
	
		
			
				
					     // Update favorite
  
			
		
	
		
			
				
					     cipher . set_favorite ( Some ( data . F avorite) ,   & headers . user . uuid ,   & mut   conn ) . await ? ;  
			
		
	
		
			
				
					     cipher . set_favorite ( Some ( data . f avorite) ,   & headers . user . uuid ,   & mut   conn ) . await ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     Ok ( Json ( cipher . to_json ( & headers . host ,   & headers . user . uuid ,   None ,   CipherSyncType ::User ,   & mut   conn ) . await ) )  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					struct  CollectionsAdminData   {  
			
		
	
		
			
				
					     CollectionI dsVec < String > ,  
			
		
	
		
			
				
					     collection_i dsVec < String > ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ put( " /ciphers/<uuid>/collections " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  put_collections_update (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < CollectionsAdminData > ,  
			
		
	
		
			
				
					     data : Json < CollectionsAdminData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -725,7 +709,7 @@ async fn put_collections_update( 
			
		
	
		
			
				
					#[ post( " /ciphers/<uuid>/collections " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_collections_update (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < CollectionsAdminData > ,  
			
		
	
		
			
				
					     data : Json < CollectionsAdminData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -736,7 +720,7 @@ async fn post_collections_update( 
			
		
	
		
			
				
					#[ put( " /ciphers/<uuid>/collections-admin " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  put_collections_admin (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < CollectionsAdminData > ,  
			
		
	
		
			
				
					     data : Json < CollectionsAdminData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -747,12 +731,12 @@ async fn put_collections_admin( 
			
		
	
		
			
				
					#[ post( " /ciphers/<uuid>/collections-admin " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_collections_admin (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < CollectionsAdminData > ,  
			
		
	
		
			
				
					     data : Json < CollectionsAdminData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					     let   data : CollectionsAdminData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data : CollectionsAdminData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   cipher   =   match   Cipher ::find_by_uuid ( uuid ,   & mut   conn ) . await   {  
			
		
	
		
			
				
					         Some ( cipher )   = >   cipher ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -763,7 +747,7 @@ async fn post_collections_admin( 
			
		
	
		
			
				
					         err ! ( "Cipher is not write accessible" )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   posted_collections : HashSet < String >   =   data . CollectionI ds. iter ( ) . cloned ( ) . collect ( ) ;  
			
		
	
		
			
				
					     let   posted_collections : HashSet < String >   =   data . collection_i ds. iter ( ) . cloned ( ) . collect ( ) ;  
			
		
	
		
			
				
					     let   current_collections : HashSet < String >   =  
			
		
	
		
			
				
					         cipher . get_collections ( headers . user . uuid . clone ( ) ,   & mut   conn ) . await . iter ( ) . cloned ( ) . collect ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -811,21 +795,21 @@ async fn post_collections_admin( 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					struct  ShareCipherData   {  
			
		
	
		
			
				
					     C ipherCipherData ,  
			
		
	
		
			
				
					     CollectionI dsVec < String > ,  
			
		
	
		
			
				
					     c ipherCipherData ,  
			
		
	
		
			
				
					     collection_i dsVec < String > ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ post( " /ciphers/<uuid>/share " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_cipher_share (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < ShareCipherData > ,  
			
		
	
		
			
				
					     data : Json < ShareCipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					     let   data : ShareCipherData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data : ShareCipherData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     share_cipher_by_uuid ( uuid ,   data ,   & headers ,   & mut   conn ,   & nt ) . await  
			
		
	
		
			
				
					}  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -833,53 +817,53 @@ async fn post_cipher_share( 
			
		
	
		
			
				
					#[ put( " /ciphers/<uuid>/share " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  put_cipher_share (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < ShareCipherData > ,  
			
		
	
		
			
				
					     data : Json < ShareCipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					     let   data : ShareCipherData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data : ShareCipherData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     share_cipher_by_uuid ( uuid ,   data ,   & headers ,   & mut   conn ,   & nt ) . await  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					struct  ShareSelectedCipherData   {  
			
		
	
		
			
				
					     C iphersVec < CipherData > ,  
			
		
	
		
			
				
					     CollectionI dsVec < String > ,  
			
		
	
		
			
				
					     c iphersVec < CipherData > ,  
			
		
	
		
			
				
					     collection_i dsVec < String > ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ put( " /ciphers/share " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  put_cipher_share_selected (  
			
		
	
		
			
				
					     data : JsonUpcase  < ShareSelectedCipherData > ,  
			
		
	
		
			
				
					     data : Json < ShareSelectedCipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					     let   mut   data : ShareSelectedCipherData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   mut   data : ShareSelectedCipherData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   data . C iphers. is_empty ( )   {  
			
		
	
		
			
				
					     if   data . c iphers. is_empty ( )   {  
			
		
	
		
			
				
					         err ! ( "You must select at least one cipher." )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   data . CollectionI ds. is_empty ( )   {  
			
		
	
		
			
				
					     if   data . collection_i ds. is_empty ( )   {  
			
		
	
		
			
				
					         err ! ( "You must select at least one collection." )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     for   cipher   in   data . C iphers. iter ( )   {  
			
		
	
		
			
				
					         if   cipher . I d. is_none ( )   {  
			
		
	
		
			
				
					     for   cipher   in   data . c iphers. iter ( )   {  
			
		
	
		
			
				
					         if   cipher . i d. is_none ( )   {  
			
		
	
		
			
				
					             err ! ( "Request missing ids field" )  
			
		
	
		
			
				
					         }  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     while   let   Some ( cipher )   =   data . C iphers. pop ( )   {  
			
		
	
		
			
				
					     while   let   Some ( cipher )   =   data . c iphers. pop ( )   {  
			
		
	
		
			
				
					         let   mut   shared_cipher_data   =   ShareCipherData   {  
			
		
	
		
			
				
					             Cipher : cipher ,  
			
		
	
		
			
				
					             CollectionIds : data . CollectionI ds. clone ( ) ,  
			
		
	
		
			
				
					             cipher ,  
			
		
	
		
			
				
					             collection_ids : data . collection_i ds. clone ( ) ,  
			
		
	
		
			
				
					         } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         match   shared_cipher_data . Cipher . I d. take ( )   {  
			
		
	
		
			
				
					         match   shared_cipher_data . cipher . i d. take ( )   {  
			
		
	
		
			
				
					             Some ( id )   = >   share_cipher_by_uuid ( & id ,   shared_cipher_data ,   & headers ,   & mut   conn ,   & nt ) . await ? ,  
			
		
	
		
			
				
					             None   = >   err ! ( "Request missing ids field" ) ,  
			
		
	
		
			
				
					         } ;  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -908,8 +892,8 @@ async fn share_cipher_by_uuid( 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   mut   shared_to_collections   =   vec ! [ ] ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   let   Some ( organization_uuid )   =   & data . Cipher . OrganizationI d  {  
			
		
	
		
			
				
					         for   uuid   in   & data . CollectionI ds  {  
			
		
	
		
			
				
					     if   let   Some ( organization_uuid )   =   & data . cipher . organization_i d  {  
			
		
	
		
			
				
					         for   uuid   in   & data . collection_i ds  {  
			
		
	
		
			
				
					             match   Collection ::find_by_uuid_and_org ( uuid ,   organization_uuid ,   conn ) . await   {  
			
		
	
		
			
				
					                 None   = >   err ! ( "Invalid collection ID provided" ) ,  
			
		
	
		
			
				
					                 Some ( collection )   = >   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -925,13 +909,13 @@ async fn share_cipher_by_uuid( 
			
		
	
		
			
				
					     } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     // When LastKnownRevisionDate is None, it is a new cipher, so send CipherCreate.
  
			
		
	
		
			
				
					     let   ut   =   if   data . Cipher . LastKnownRevisionD ate. is_some ( )   {  
			
		
	
		
			
				
					     let   ut   =   if   data . cipher . last_known_revision_d ate. is_some ( )   {  
			
		
	
		
			
				
					         UpdateType ::SyncCipherUpdate  
			
		
	
		
			
				
					     }   else   {  
			
		
	
		
			
				
					         UpdateType ::SyncCipherCreate  
			
		
	
		
			
				
					     } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     update_cipher_from_data ( & mut   cipher ,   data . C ipher,   headers ,   Some ( shared_to_collections ) ,   conn ,   nt ,   ut ) . await ? ;  
			
		
	
		
			
				
					     update_cipher_from_data ( & mut   cipher ,   data . c ipher,   headers ,   Some ( shared_to_collections ) ,   conn ,   nt ,   ut ) . await ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     Ok ( Json ( cipher . to_json ( & headers . host ,   & headers . user . uuid ,   None ,   CipherSyncType ::User ,   conn ) . await ) )  
			
		
	
		
			
				
					}  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -961,12 +945,12 @@ async fn get_attachment(uuid: &str, attachment_id: &str, headers: Headers, mut c 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					struct  AttachmentRequestData   {  
			
		
	
		
			
				
					     K eyString ,  
			
		
	
		
			
				
					     FileN ameString ,  
			
		
	
		
			
				
					     FileS izeNumberOrString ,  
			
		
	
		
			
				
					     AdminR equestOption < bool > ,   // true when attaching from an org vault view
  
			
		
	
		
			
				
					     k eyString ,  
			
		
	
		
			
				
					     file_n ameString ,  
			
		
	
		
			
				
					     file_s izeNumberOrString ,  
			
		
	
		
			
				
					     admin_r equestOption < bool > ,   // true when attaching from an org vault view
  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					enum  FileUploadType   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -981,7 +965,7 @@ enum FileUploadType { 
			
		
	
		
			
				
					#[ post( " /ciphers/<uuid>/attachment/v2 " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  post_attachment_v2 (  
			
		
	
		
			
				
					     uuid : & str ,  
			
		
	
		
			
				
					     data : JsonUpcase  < AttachmentRequestData > ,  
			
		
	
		
			
				
					     data : Json < AttachmentRequestData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -994,28 +978,28 @@ async fn post_attachment_v2( 
			
		
	
		
			
				
					         err ! ( "Cipher is not write accessible" )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   data : AttachmentRequestData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   file_size   =   data . FileS ize. into_i64 ( ) ? ;  
			
		
	
		
			
				
					     let   data : AttachmentRequestData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					     let   file_size   =   data . file_s ize. into_i64 ( ) ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   file_size   <   0   {  
			
		
	
		
			
				
					         err ! ( "Attachment size can't be negative" )  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					     let   attachment_id   =   crypto ::generate_attachment_id ( ) ;  
			
		
	
		
			
				
					     let   attachment   =  
			
		
	
		
			
				
					         Attachment ::new ( attachment_id . clone ( ) ,   cipher . uuid . clone ( ) ,   data . FileN ame,   file_size ,   Some ( data . K ey) ) ;  
			
		
	
		
			
				
					         Attachment ::new ( attachment_id . clone ( ) ,   cipher . uuid . clone ( ) ,   data . file_n ame,   file_size ,   Some ( data . k ey) ) ;  
			
		
	
		
			
				
					     attachment . save ( & mut   conn ) . await . expect ( "Error saving attachment" ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   url   =   format ! ( "/ciphers/{}/attachment/{}" ,   cipher . uuid ,   attachment_id ) ;  
			
		
	
		
			
				
					     let   response_key   =   match   data . AdminR equest  {  
			
		
	
		
			
				
					         Some ( b )   if   b   = >   "C ipherMiniResponse" ,  
			
		
	
		
			
				
					         _   = >   "C ipherResponse" ,  
			
		
	
		
			
				
					     let   response_key   =   match   data . admin_r equest  {  
			
		
	
		
			
				
					         Some ( b )   if   b   = >   "c ipherMiniResponse" ,  
			
		
	
		
			
				
					         _   = >   "c ipherResponse" ,  
			
		
	
		
			
				
					     } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     Ok ( Json ( json ! ( {   // AttachmentUploadDataResponseModel
  
			
		
	
		
			
				
					         "O bject" : "attachment-fileUpload" ,  
			
		
	
		
			
				
					         "A ttachmentId" : attachment_id ,  
			
		
	
		
			
				
					         "U rl" : url ,  
			
		
	
		
			
				
					         "F ileUploadType" : FileUploadType ::Direct   as   i32 ,  
			
		
	
		
			
				
					         "o bject" : "attachment-fileUpload" ,  
			
		
	
		
			
				
					         "a ttachmentId" : attachment_id ,  
			
		
	
		
			
				
					         "u rl" : url ,  
			
		
	
		
			
				
					         "f ileUploadType" : FileUploadType ::Direct   as   i32 ,  
			
		
	
		
			
				
					         response_key : cipher . to_json ( & headers . host ,   & headers . user . uuid ,   None ,   CipherSyncType ::User ,   & mut   conn ) . await ,  
			
		
	
		
			
				
					     } ) ) )  
			
		
	
		
			
				
					}  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1350,38 +1334,23 @@ async fn delete_cipher_admin(uuid: &str, headers: Headers, mut conn: DbConn, nt: 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ delete( " /ciphers " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  delete_cipher_selected (  
			
		
	
		
			
				
					     data : JsonUpcase < Value > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					async   fn  delete_cipher_selected ( data : Json < Value > ,   headers : Headers ,   conn : DbConn ,   nt : Notify < '_ > )   -> EmptyResult   {  
			
		
	
		
			
				
					     _delete_multiple_ciphers ( data ,   headers ,   conn ,   false ,   nt ) . await   // permanent delete
  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ post( " /ciphers/delete " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  delete_cipher_selected_post (  
			
		
	
		
			
				
					     data : JsonUpcase < Value > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					async   fn  delete_cipher_selected_post ( data : Json < Value > ,   headers : Headers ,   conn : DbConn ,   nt : Notify < '_ > )   -> EmptyResult   {  
			
		
	
		
			
				
					     _delete_multiple_ciphers ( data ,   headers ,   conn ,   false ,   nt ) . await   // permanent delete
  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ put( " /ciphers/delete " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  delete_cipher_selected_put (  
			
		
	
		
			
				
					     data : JsonUpcase < Value > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					async   fn  delete_cipher_selected_put ( data : Json < Value > ,   headers : Headers ,   conn : DbConn ,   nt : Notify < '_ > )   -> EmptyResult   {  
			
		
	
		
			
				
					     _delete_multiple_ciphers ( data ,   headers ,   conn ,   true ,   nt ) . await   // soft delete
  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ delete( " /ciphers/admin " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  delete_cipher_selected_admin (  
			
		
	
		
			
				
					     data : JsonUpcase  < Value > ,  
			
		
	
		
			
				
					     data : Json < Value > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1391,7 +1360,7 @@ async fn delete_cipher_selected_admin( 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ post( " /ciphers/delete-admin " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  delete_cipher_selected_post_admin (  
			
		
	
		
			
				
					     data : JsonUpcase  < Value > ,  
			
		
	
		
			
				
					     data : Json < Value > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1401,7 +1370,7 @@ async fn delete_cipher_selected_post_admin( 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ put( " /ciphers/delete-admin " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  delete_cipher_selected_put_admin (  
			
		
	
		
			
				
					     data : JsonUpcase  < Value > ,  
			
		
	
		
			
				
					     data : Json < Value > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1420,33 +1389,28 @@ async fn restore_cipher_put_admin(uuid: &str, headers: Headers, mut conn: DbConn 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ put( " /ciphers/restore " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  restore_cipher_selected (  
			
		
	
		
			
				
					     data : JsonUpcase < Value > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					async   fn  restore_cipher_selected ( data : Json < Value > ,   headers : Headers ,   mut   conn : DbConn ,   nt : Notify < '_ > )   -> JsonResult   {  
			
		
	
		
			
				
					     _restore_multiple_ciphers ( data ,   & headers ,   & mut   conn ,   & nt ) . await  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ derive(Deserialize) ]  
			
		
	
		
			
				
					#[ allow(non_snake_case )]  
			
		
	
		
			
				
					#[ serde(rename_all =  " camelCase " ) ]  
			
		
	
		
			
				
					struct  MoveCipherData   {  
			
		
	
		
			
				
					     FolderI dOption < String > ,  
			
		
	
		
			
				
					     I dsVec < String > ,  
			
		
	
		
			
				
					     folder_i dOption < String > ,  
			
		
	
		
			
				
					     i dsVec < String > ,  
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ post( " /ciphers/move " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  move_cipher_selected (  
			
		
	
		
			
				
					     data : JsonUpcase  < MoveCipherData > ,  
			
		
	
		
			
				
					     data : Json < MoveCipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					     let   data   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					     let   user_uuid   =   headers . user . uuid ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     if   let   Some ( ref   folder_id )   =   data . FolderI d  {  
			
		
	
		
			
				
					     if   let   Some ( ref   folder_id )   =   data . folder_i d  {  
			
		
	
		
			
				
					         match   Folder ::find_by_uuid ( folder_id ,   & mut   conn ) . await   {  
			
		
	
		
			
				
					             Some ( folder )   = >   {  
			
		
	
		
			
				
					                 if   folder . user_uuid   ! =   user_uuid   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1457,7 +1421,7 @@ async fn move_cipher_selected( 
			
		
	
		
			
				
					         }  
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     for   uuid   in   data . I ds  {  
			
		
	
		
			
				
					     for   uuid   in   data . i ds  {  
			
		
	
		
			
				
					         let   cipher   =   match   Cipher ::find_by_uuid ( & uuid ,   & mut   conn ) . await   {  
			
		
	
		
			
				
					             Some ( cipher )   = >   cipher ,  
			
		
	
		
			
				
					             None   = >   err ! ( "Cipher doesn't exist" ) ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1468,7 +1432,7 @@ async fn move_cipher_selected( 
			
		
	
		
			
				
					         }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         // Move cipher
  
			
		
	
		
			
				
					         cipher . move_to_folder ( data . FolderI d. clone ( ) ,   & user_uuid ,   & mut   conn ) . await ? ;  
			
		
	
		
			
				
					         cipher . move_to_folder ( data . folder_i d. clone ( ) ,   & user_uuid ,   & mut   conn ) . await ? ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					         nt . send_cipher_update (  
			
		
	
		
			
				
					             UpdateType ::SyncCipherUpdate ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1486,7 +1450,7 @@ async fn move_cipher_selected( 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					#[ put( " /ciphers/move " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  move_cipher_selected_put (  
			
		
	
		
			
				
					     data : JsonUpcase  < MoveCipherData > ,  
			
		
	
		
			
				
					     data : Json < MoveCipherData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1503,12 +1467,12 @@ struct OrganizationId { 
			
		
	
		
			
				
					#[ post( " /ciphers/purge?<organization..> " , data =  " <data> " ) ]  
			
		
	
		
			
				
					async   fn  delete_all (  
			
		
	
		
			
				
					     organization : Option < OrganizationId > ,  
			
		
	
		
			
				
					     data : JsonUpcase  < PasswordOrOtpData > ,  
			
		
	
		
			
				
					     data : Json < PasswordOrOtpData > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					     let   data : PasswordOrOtpData   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data : PasswordOrOtpData   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					     let   mut   user   =   headers . user ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     data . validate ( & user ,   true ,   & mut   conn ) . await ? ;  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1616,13 +1580,13 @@ async fn _delete_cipher_by_uuid( 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					async   fn  _delete_multiple_ciphers (  
			
		
	
		
			
				
					     data : JsonUpcase  < Value > ,  
			
		
	
		
			
				
					     data : Json < Value > ,  
			
		
	
		
			
				
					     headers : Headers ,  
			
		
	
		
			
				
					     mut   conn : DbConn ,  
			
		
	
		
			
				
					     soft_delete : bool ,  
			
		
	
		
			
				
					     nt : Notify < '_ > ,  
			
		
	
		
			
				
					)   -> EmptyResult   {  
			
		
	
		
			
				
					     let   data : Value   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data : Value   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   uuids   =   match   data . get ( "Ids" )   {  
			
		
	
		
			
				
					         Some ( ids )   = >   match   ids . as_array ( )   {  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -1681,12 +1645,12 @@ async fn _restore_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &mut DbCon 
			
		
	
		
			
				
					}  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					async   fn  _restore_multiple_ciphers (  
			
		
	
		
			
				
					     data : JsonUpcase  < Value > ,  
			
		
	
		
			
				
					     data : Json < Value > ,  
			
		
	
		
			
				
					     headers : & Headers ,  
			
		
	
		
			
				
					     conn : & mut   DbConn ,  
			
		
	
		
			
				
					     nt : & Notify < '_ > ,  
			
		
	
		
			
				
					)   -> JsonResult   {  
			
		
	
		
			
				
					     let   data : Value   =   data . into_inner ( ) . data ;  
			
		
	
		
			
				
					     let   data : Value   =   data . into_inner ( ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     let   uuids   =   match   data . get ( "Ids" )   {  
			
		
	
		
			
				
					         Some ( ids )   = >   match   ids . as_array ( )   {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -1705,9 +1669,9 @@ async fn _restore_multiple_ciphers( 
			
		
	
		
			
				
					     }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					     Ok ( Json ( json ! ( {  
			
		
	
		
			
				
					       "D ata" : ciphers ,  
			
		
	
		
			
				
					       "O bject" : "list" ,  
			
		
	
		
			
				
					       "C ontinuationToken" : null  
			
		
	
		
			
				
					       "d ata" : ciphers ,  
			
		
	
		
			
				
					       "o bject" : "list" ,  
			
		
	
		
			
				
					       "c ontinuationToken" : null  
			
		
	
		
			
				
					     } ) ) )  
			
		
	
		
			
				
					}