From 062ae4dd59a4e851900d63d0ba04a46e20a9f49d Mon Sep 17 00:00:00 2001 From: mprasil Date: Wed, 29 Aug 2018 14:22:03 +0100 Subject: [PATCH 1/2] Allow non-Admin user to share to collection (fixes #157) (#159) * Allow non-Admin user to share to collection (fixes #157) * Better handling of collection sharing --- src/api/core/ciphers.rs | 42 ++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index 21b01bb..fe6caf4 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -127,26 +127,24 @@ fn post_ciphers(data: JsonUpcase, headers: Headers, conn: DbConn) -> let data: CipherData = data.into_inner().data; let mut cipher = Cipher::new(data.Type, data.Name.clone()); - update_cipher_from_data(&mut cipher, data, &headers, true, &conn)?; + update_cipher_from_data(&mut cipher, data, &headers, false, &conn)?; Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, &conn))) } -fn update_cipher_from_data(cipher: &mut Cipher, data: CipherData, headers: &Headers, is_new_or_shared: bool, conn: &DbConn) -> EmptyResult { - if is_new_or_shared { - if let Some(org_id) = data.OrganizationId { - match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &conn) { - None => err!("You don't have permission to add item to organization"), - Some(org_user) => if org_user.has_full_access() { - cipher.organization_uuid = Some(org_id); - cipher.user_uuid = None; - } else { - err!("You don't have permission to add cipher directly to organization") - } +fn update_cipher_from_data(cipher: &mut Cipher, data: CipherData, headers: &Headers, shared_to_collection: bool, conn: &DbConn) -> EmptyResult { + if let Some(org_id) = data.OrganizationId { + match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &conn) { + None => err!("You don't have permission to add item to organization"), + Some(org_user) => if shared_to_collection || org_user.has_full_access() { + cipher.organization_uuid = Some(org_id); + cipher.user_uuid = None; + } else { + err!("You don't have permission to add cipher directly to organization") } - } else { - cipher.user_uuid = Some(headers.user.uuid.clone()); } + } else { + cipher.user_uuid = Some(headers.user.uuid.clone()); } if let Some(ref folder_id) = data.FolderId { @@ -243,7 +241,7 @@ fn post_ciphers_import(data: JsonUpcase, headers: Headers, conn: DbC .map(|i| folders[*i].uuid.clone()); let mut cipher = Cipher::new(cipher_data.Type, cipher_data.Name.clone()); - update_cipher_from_data(&mut cipher, cipher_data, &headers, true, &conn)?; + update_cipher_from_data(&mut cipher, cipher_data, &headers, false, &conn)?; cipher.move_to_folder(folder_uuid, &headers.user.uuid.clone(), &conn).ok(); } @@ -422,22 +420,28 @@ fn share_cipher_by_uuid(uuid: &str, data: ShareCipherData, headers: &Headers, co None => err!("Cipher doesn't exist") }; - match data.Cipher.OrganizationId { + match data.Cipher.OrganizationId.clone() { None => err!("Organization id not provided"), - Some(_) => { - update_cipher_from_data(&mut cipher, data.Cipher, &headers, true, &conn)?; + Some(organization_uuid) => { + let mut shared_to_collection = false; for uuid in &data.CollectionIds { match Collection::find_by_uuid(uuid, &conn) { None => err!("Invalid collection ID provided"), Some(collection) => { if collection.is_writable_by_user(&headers.user.uuid, &conn) { - CollectionCipher::save(&cipher.uuid.clone(), &collection.uuid, &conn); + if collection.org_uuid == organization_uuid { + CollectionCipher::save(&cipher.uuid.clone(), &collection.uuid, &conn); + shared_to_collection = true; + } else { + err!("Collection does not belong to organization") + } } else { err!("No rights to modify the collection") } } } } + update_cipher_from_data(&mut cipher, data.Cipher, &headers, shared_to_collection, &conn)?; Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, &conn))) } From fe473b9e75342c76a2002f9a24bff4b218e91aae Mon Sep 17 00:00:00 2001 From: Baelyk Date: Wed, 29 Aug 2018 08:22:19 -0500 Subject: [PATCH 2/2] `Attachment::save()` returns Result instead of bool (#161) Returning a result instead of a bool as per #6 --- src/api/core/ciphers.rs | 13 ++++++++----- src/db/models/attachment.rs | 12 +++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index fe6caf4..f7d74d8 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -375,11 +375,11 @@ fn put_cipher_share_seleted(data: JsonUpcase, headers: if data.Ciphers.len() == 0 { err!("You must select at least one cipher.") } - + if data.CollectionIds.len() == 0 { err!("You must select at least one collection.") } - + for cipher in data.Ciphers.iter() { match cipher.Id { Some(ref id) => cipher_ids.push(id.to_string()), @@ -388,7 +388,7 @@ fn put_cipher_share_seleted(data: JsonUpcase, headers: } let attachments = Attachment::find_by_ciphers(cipher_ids, &conn); - + if attachments.len() > 0 { err!("Ciphers should not have any attachments.") } @@ -492,7 +492,10 @@ fn post_attachment(uuid: String, data: Data, content_type: &ContentType, headers }; let attachment = Attachment::new(file_name, cipher.uuid.clone(), name, size); - attachment.save(&conn); + match attachment.save(&conn) { + Ok(()) => (), + Err(_) => println!("Error: failed to save attachment") + }; }).expect("Error processing multipart data"); Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, &conn))) @@ -654,7 +657,7 @@ fn delete_all(data: JsonUpcase, headers: Headers, conn: DbConn) -> for f in Folder::find_by_user(&user.uuid, &conn) { if f.delete(&conn).is_err() { err!("Failed deleting folder") - } + } } Ok(()) diff --git a/src/db/models/attachment.rs b/src/db/models/attachment.rs index 66d5b72..9c8eeef 100644 --- a/src/db/models/attachment.rs +++ b/src/db/models/attachment.rs @@ -53,13 +53,11 @@ use db::schema::attachments; /// Database methods impl Attachment { - pub fn save(&self, conn: &DbConn) -> bool { - match diesel::replace_into(attachments::table) + pub fn save(&self, conn: &DbConn) -> QueryResult<()> { + diesel::replace_into(attachments::table) .values(self) - .execute(&**conn) { - Ok(1) => true, // One row inserted - _ => false, - } + .execute(&**conn) + .and(Ok(())) } pub fn delete(self, conn: &DbConn) -> QueryResult<()> { @@ -67,7 +65,7 @@ impl Attachment { use std::{thread, time}; let mut retries = 10; - + loop { match diesel::delete( attachments::table.filter(