@ -100,24 +100,18 @@ fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> Json<Value> {
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 ( )
let collections_json : Vec < Value > =
. map ( | c | c . to_json_details ( & headers . user . uuid , & conn ) )
collections . iter ( ) . map ( | c | c . to_json_details ( & headers . user . uuid , & conn ) ) . collect ( ) ;
. 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 ( ) ;
let ciphers = Cipher ::find_by_user_visible ( & headers . user . uuid , & conn ) ;
let ciphers = Cipher ::find_by_user_visible ( & headers . user . uuid , & conn ) ;
let ciphers_json : Vec < Value > = ciphers
let ciphers_json : Vec < Value > =
. iter ( )
ciphers . iter ( ) . map ( | c | c . to_json ( & headers . host , & headers . user . uuid , & conn ) ) . collect ( ) ;
. map ( | c | c . to_json ( & headers . host , & headers . user . uuid , & conn ) )
. collect ( ) ;
let sends = Send ::find_by_user ( & headers . user . uuid , & conn ) ;
let sends = Send ::find_by_user ( & headers . user . uuid , & conn ) ;
let sends_json : Vec < Value > = sends
let sends_json : Vec < Value > = sends . iter ( ) . map ( | s | s . to_json ( ) ) . collect ( ) ;
. iter ( )
. map ( | s | s . to_json ( ) )
. collect ( ) ;
let domains_json = if data . exclude_domains {
let domains_json = if data . exclude_domains {
Value ::Null
Value ::Null
@ -142,10 +136,8 @@ fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> Json<Value> {
fn get_ciphers ( headers : Headers , conn : DbConn ) -> Json < Value > {
fn get_ciphers ( headers : Headers , conn : DbConn ) -> Json < Value > {
let ciphers = Cipher ::find_by_user_visible ( & headers . user . uuid , & conn ) ;
let ciphers = Cipher ::find_by_user_visible ( & headers . user . uuid , & conn ) ;
let ciphers_json : Vec < Value > = ciphers
let ciphers_json : Vec < Value > =
. iter ( )
ciphers . iter ( ) . map ( | c | c . to_json ( & headers . host , & headers . user . uuid , & conn ) ) . collect ( ) ;
. map ( | c | c . to_json ( & headers . host , & headers . user . uuid , & conn ) )
. collect ( ) ;
Json ( json ! ( {
Json ( json ! ( {
"Data" : ciphers_json ,
"Data" : ciphers_json ,
@ -246,7 +238,7 @@ fn post_ciphers_create(data: JsonUpcase<ShareCipherData>, headers: Headers, conn
// Check if there are one more more collections selected when this cipher is part of an organization.
// 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.
// err if this is not the case before creating an empty cipher.
if data . Cipher . OrganizationId . is_some ( ) & & data . CollectionIds . is_empty ( ) {
if data . Cipher . OrganizationId . is_some ( ) & & data . CollectionIds . is_empty ( ) {
err ! ( "You must select at least one collection." ) ;
err ! ( "You must select at least one collection." ) ;
}
}
@ -288,17 +280,12 @@ fn post_ciphers(data: JsonUpcase<CipherData>, headers: Headers, conn: DbConn, nt
/// 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
fn enforce_personal_ownership_policy (
fn enforce_personal_ownership_policy ( data : & CipherData , headers : & Headers , conn : & DbConn ) -> EmptyResult {
data : & CipherData ,
headers : & Headers ,
conn : & DbConn
) -> EmptyResult {
if data . OrganizationId . is_none ( ) {
if data . 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 ;
if OrgPolicy ::is_applicable_to_user ( user_uuid , policy_type , conn ) {
if OrgPolicy ::is_applicable_to_user ( user_uuid , policy_type , conn ) {
err ! ( " Due to an Enterprise Policy , you are restricted from \
err ! ( "Due to an Enterprise Policy, you are restricted from saving items to your personal vault." )
saving items to your personal vault . " )
}
}
}
}
Ok ( ( ) )
Ok ( ( ) )
@ -317,11 +304,12 @@ pub fn update_cipher_from_data(
// Check that the client isn't updating an existing cipher with stale data.
// Check that the client isn't updating an existing cipher with stale data.
if let Some ( dt ) = data . LastKnownRevisionDate {
if let Some ( dt ) = data . LastKnownRevisionDate {
match NaiveDateTime ::parse_from_str ( & dt , "%+" ) { // ISO 8601 format
match NaiveDateTime ::parse_from_str ( & dt , "%+" ) {
Err ( err ) = >
// ISO 8601 format
warn ! ( "Error parsing LastKnownRevisionDate '{}': {}" , dt , err ) ,
Err ( err ) = > warn ! ( "Error parsing LastKnownRevisionDate '{}': {}" , dt , err ) ,
Ok ( dt ) if cipher . updated_at . signed_duration_since ( dt ) . num_seconds ( ) > 1 = >
Ok ( dt ) if cipher . updated_at . signed_duration_since ( dt ) . num_seconds ( ) > 1 = > {
err ! ( "The client copy of this cipher is out of date. Resync the client and try again." ) ,
err ! ( "The client copy of this cipher is out of date. Resync the client and try again." )
}
Ok ( _ ) = > ( ) ,
Ok ( _ ) = > ( ) ,
}
}
}
}
@ -394,12 +382,9 @@ pub fn update_cipher_from_data(
// But, we at least know we do not need to store and return this specific key.
// 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 {
fn _clean_cipher_data ( mut json_data : Value ) -> Value {
if json_data . is_array ( ) {
if json_data . is_array ( ) {
json_data . as_array_mut ( )
json_data . as_array_mut ( ) . unwrap ( ) . iter_mut ( ) . for_each ( | ref mut f | {
. unwrap ( )
f . as_object_mut ( ) . unwrap ( ) . remove ( "Response" ) ;
. iter_mut ( )
} ) ;
. for_each ( | ref mut f | {
f . as_object_mut ( ) . unwrap ( ) . remove ( "Response" ) ;
} ) ;
} ;
} ;
json_data
json_data
}
}
@ -421,13 +406,13 @@ pub fn update_cipher_from_data(
data [ "Uris" ] = _clean_cipher_data ( data [ "Uris" ] . clone ( ) ) ;
data [ "Uris" ] = _clean_cipher_data ( data [ "Uris" ] . clone ( ) ) ;
}
}
data
data
} ,
}
None = > err ! ( "Data missing" ) ,
None = > err ! ( "Data missing" ) ,
} ;
} ;
cipher . name = data . Name ;
cipher . name = data . Name ;
cipher . notes = data . Notes ;
cipher . notes = data . Notes ;
cipher . fields = data . Fields . map ( | f | _clean_cipher_data ( 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 ( ) ) ;
@ -602,11 +587,8 @@ fn post_collections_admin(
}
}
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 > = cipher
let current_collections : HashSet < String > =
. get_collections ( & headers . user . uuid , & conn )
cipher . get_collections ( & headers . user . uuid , & conn ) . iter ( ) . cloned ( ) . collect ( ) ;
. iter ( )
. cloned ( )
. collect ( ) ;
for collection in posted_collections . symmetric_difference ( & current_collections ) {
for collection in posted_collections . symmetric_difference ( & current_collections ) {
match Collection ::find_by_uuid ( & collection , & conn ) {
match Collection ::find_by_uuid ( & collection , & conn ) {
@ -842,24 +824,25 @@ fn post_attachment(
let file_name = HEXLOWER . encode ( & crypto ::get_random ( vec! [ 0 ; 10 ] ) ) ;
let file_name = HEXLOWER . encode ( & crypto ::get_random ( vec! [ 0 ; 10 ] ) ) ;
let path = base_path . join ( & file_name ) ;
let path = base_path . join ( & file_name ) ;
let size = match field . data . save ( ) . memory_threshold ( 0 ) . size_limit ( size_limit ) . with_path ( path . clone ( ) ) {
let size =
SaveResult ::Full ( SavedData ::File ( _ , size ) ) = > size as i32 ,
match field . data . save ( ) . memory_threshold ( 0 ) . size_limit ( size_limit ) . with_path ( path . clone ( ) ) {
SaveResult ::Full ( other ) = > {
SaveResult ::Full ( SavedData ::File ( _ , size ) ) = > size as i32 ,
std ::fs ::remove_file ( path ) . ok ( ) ;
SaveResult ::Full ( other ) = > {
error = Some ( format! ( "Attachment is not a file: {:?}" , other ) ) ;
std ::fs ::remove_file ( path ) . ok ( ) ;
return ;
error = Some ( format! ( "Attachment is not a file: {:?}" , other ) ) ;
}
return ;
SaveResult ::Partial ( _ , reason ) = > {
}
std ::fs ::remove_file ( path ) . ok ( ) ;
SaveResult ::Partial ( _ , reason ) = > {
error = Some ( format! ( "Attachment size limit exceeded with this file: {:?}" , reason ) ) ;
std ::fs ::remove_file ( path ) . ok ( ) ;
return ;
error = Some ( format! ( "Attachment size limit exceeded with this file: {:?}" , reason ) ) ;
}
return ;
SaveResult ::Error ( e ) = > {
}
std ::fs ::remove_file ( path ) . ok ( ) ;
SaveResult ::Error ( e ) = > {
error = Some ( format! ( "Error: {:?}" , e ) ) ;
std ::fs ::remove_file ( path ) . ok ( ) ;
return ;
error = Some ( format! ( "Error: {:?}" , e ) ) ;
}
return ;
} ;
}
} ;
let mut attachment = Attachment ::new ( file_name , cipher . uuid . clone ( ) , name , size ) ;
let mut attachment = Attachment ::new ( file_name , cipher . uuid . clone ( ) , name , size ) ;
attachment . akey = attachment_key . clone ( ) ;
attachment . akey = attachment_key . clone ( ) ;
@ -994,12 +977,22 @@ fn delete_cipher_selected_admin(data: JsonUpcase<Value>, headers: Headers, conn:
}
}
#[ post( " /ciphers/delete-admin " , data = " <data> " ) ]
#[ post( " /ciphers/delete-admin " , data = " <data> " ) ]
fn delete_cipher_selected_post_admin ( data : JsonUpcase < Value > , headers : Headers , conn : DbConn , nt : Notify ) -> EmptyResult {
fn delete_cipher_selected_post_admin (
data : JsonUpcase < Value > ,
headers : Headers ,
conn : DbConn ,
nt : Notify ,
) -> EmptyResult {
delete_cipher_selected_post ( data , headers , conn , nt )
delete_cipher_selected_post ( data , headers , conn , nt )
}
}
#[ put( " /ciphers/delete-admin " , data = " <data> " ) ]
#[ put( " /ciphers/delete-admin " , data = " <data> " ) ]
fn delete_cipher_selected_put_admin ( data : JsonUpcase < Value > , headers : Headers , conn : DbConn , nt : Notify ) -> EmptyResult {
fn delete_cipher_selected_put_admin (
data : JsonUpcase < Value > ,
headers : Headers ,
conn : DbConn ,
nt : Notify ,
) -> EmptyResult {
delete_cipher_selected_put ( data , headers , conn , nt )
delete_cipher_selected_put ( data , headers , conn , nt )
}
}
@ -1150,7 +1143,13 @@ fn _delete_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &DbConn, soft_del
Ok ( ( ) )
Ok ( ( ) )
}
}
fn _delete_multiple_ciphers ( data : JsonUpcase < Value > , headers : Headers , conn : DbConn , soft_delete : bool , nt : Notify ) -> EmptyResult {
fn _delete_multiple_ciphers (
data : JsonUpcase < Value > ,
headers : Headers ,
conn : DbConn ,
soft_delete : bool ,
nt : Notify ,
) -> EmptyResult {
let data : Value = data . into_inner ( ) . data ;
let data : Value = data . into_inner ( ) . data ;
let uuids = match data . get ( "Ids" ) {
let uuids = match data . get ( "Ids" ) {
@ -1202,7 +1201,7 @@ fn _restore_multiple_ciphers(data: JsonUpcase<Value>, headers: &Headers, conn: &
for uuid in uuids {
for uuid in uuids {
match _restore_cipher_by_uuid ( uuid , headers , conn , nt ) {
match _restore_cipher_by_uuid ( uuid , headers , conn , nt ) {
Ok ( json ) = > ciphers . push ( json . into_inner ( ) ) ,
Ok ( json ) = > ciphers . push ( json . into_inner ( ) ) ,
err = > return err
err = > return err ,
}
}
}
}