@ -91,7 +91,9 @@ fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> JsonResult {
let folders_json : Vec < Value > = folders . iter ( ) . map ( Folder ::to_json ) . collect ( ) ;
let folders_json : Vec < Value > = folders . iter ( ) . map ( Folder ::to_json ) . collect ( ) ;
let collections = Collection ::find_by_user_uuid ( & headers . user . uuid , & conn ) ;
let collections = Collection ::find_by_user_uuid ( & headers . user . uuid , & conn ) ;
let collections_json : Vec < Value > = collections . iter ( ) . map ( Collection ::to_json ) . collect ( ) ;
let collections_json : Vec < Value > = collections . iter ( )
. map ( | c | c . to_json_details ( & headers . user . uuid , & conn ) )
. collect ( ) ;
let policies = OrgPolicy ::find_by_user ( & headers . user . uuid , & conn ) ;
let policies = OrgPolicy ::find_by_user ( & headers . user . uuid , & conn ) ;
let policies_json : Vec < Value > = policies . iter ( ) . map ( OrgPolicy ::to_json ) . collect ( ) ;
let policies_json : Vec < Value > = policies . iter ( ) . map ( OrgPolicy ::to_json ) . collect ( ) ;
@ -225,6 +227,12 @@ fn post_ciphers_admin(data: JsonUpcase<ShareCipherData>, headers: Headers, conn:
fn post_ciphers_create ( data : JsonUpcase < ShareCipherData > , headers : Headers , conn : DbConn , nt : Notify ) -> JsonResult {
fn post_ciphers_create ( data : JsonUpcase < ShareCipherData > , headers : Headers , conn : DbConn , nt : Notify ) -> JsonResult {
let mut data : ShareCipherData = data . into_inner ( ) . data ;
let mut data : ShareCipherData = data . into_inner ( ) . data ;
// 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 . OrganizationId . is_some ( ) & & data . CollectionIds . is_empty ( ) {
err ! ( "You must select at least one collection." ) ;
}
// 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.
@ -323,6 +331,11 @@ pub fn update_cipher_from_data(
| | cipher . is_write_accessible_to_user ( & headers . user . uuid , & conn )
| | cipher . is_write_accessible_to_user ( & headers . user . uuid , & conn )
{
{
cipher . organization_uuid = Some ( org_id ) ;
cipher . organization_uuid = Some ( org_id ) ;
// After some discussion in PR #1329 re-added the user_uuid = None again.
// TODO: Audit/Check the whole save/update cipher chain.
// Upstream uses the user_uuid to allow a cipher added by a user to an org to still allow the user to view/edit the cipher
// even when the user has hide-passwords configured as there policy.
// Removing the line below would fix that, but we have to check which effect this would have on the rest of the code.
cipher . user_uuid = None ;
cipher . user_uuid = None ;
} else {
} else {
err ! ( "You don't have permission to add cipher directly to organization" )
err ! ( "You don't have permission to add cipher directly to organization" )
@ -366,6 +379,23 @@ pub fn update_cipher_from_data(
}
}
}
}
// Cleanup cipher data, like removing the 'Response' key.
// This key is somewhere generated during Javascript so no way for us this fix this.
// Also, upstream only retrieves keys they actually want to store, and thus skip the 'Response' key.
// We do not mind which data is in it, the keep our model more flexible when there are upstream changes.
// But, we at least know we do not need to store and return this specific key.
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 ( "Response" ) ;
} ) ;
} ;
json_data
}
let type_data_opt = match data . Type {
let type_data_opt = match data . Type {
1 = > data . Login ,
1 = > data . Login ,
2 = > data . SecureNote ,
2 = > data . SecureNote ,
@ -374,23 +404,22 @@ pub fn update_cipher_from_data(
_ = > err ! ( "Invalid type" ) ,
_ = > err ! ( "Invalid type" ) ,
} ;
} ;
let mut type_data = match type_data_opt {
let type_data = match type_data_opt {
Some ( data ) = > data ,
Some ( mut data ) = > {
// Remove the 'Response' key from the base object.
data . as_object_mut ( ) . unwrap ( ) . remove ( "Response" ) ;
// Remove the 'Response' key from every Uri.
if data [ "Uris" ] . is_array ( ) {
data [ "Uris" ] = _clean_cipher_data ( data [ "Uris" ] . clone ( ) ) ;
}
data
} ,
None = > err ! ( "Data missing" ) ,
None = > err ! ( "Data missing" ) ,
} ;
} ;
// TODO: ******* Backwards compat start **********
// To remove backwards compatibility, just delete this code,
// and remove the compat code from cipher::to_json
type_data [ "Name" ] = Value ::String ( data . Name . clone ( ) ) ;
type_data [ "Notes" ] = data . Notes . clone ( ) . map ( Value ::String ) . unwrap_or ( Value ::Null ) ;
type_data [ "Fields" ] = data . Fields . clone ( ) . unwrap_or ( Value ::Null ) ;
type_data [ "PasswordHistory" ] = data . PasswordHistory . clone ( ) . unwrap_or ( Value ::Null ) ;
// TODO: ******* Backwards compat end **********
cipher . name = data . Name ;
cipher . name = data . Name ;
cipher . notes = data . Notes ;
cipher . notes = data . Notes ;
cipher . fields = data . Fields . map ( | f | f. to_string ( ) ) ;
cipher . fields = data . Fields . map ( | f | _clean_cipher_data ( f ) . to_string ( ) ) ;
cipher . data = type_data . to_string ( ) ;
cipher . data = type_data . to_string ( ) ;
cipher . password_history = data . PasswordHistory . map ( | f | f . to_string ( ) ) ;
cipher . password_history = data . PasswordHistory . map ( | f | f . to_string ( ) ) ;
@ -1064,7 +1093,6 @@ fn delete_all(
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 ) ? ;
Cipher ::delete_all_by_organization ( & org_data . org_id , & conn ) ? ;
Collection ::delete_all_by_organization ( & org_data . org_id , & conn ) ? ;
nt . send_user_update ( UpdateType ::Vault , & user ) ;
nt . send_user_update ( UpdateType ::Vault , & user ) ;
Ok ( ( ) )
Ok ( ( ) )
} else {
} else {