mirror of
				https://github.com/dani-garcia/vaultwarden.git
				synced 2025-10-29 01:10:01 +02:00 
			
		
		
		
	Implemented bulk cipher share (share selected) #100
This commit is contained in:
		| @@ -87,6 +87,8 @@ fn get_cipher_details(uuid: String, headers: Headers, conn: DbConn) -> JsonResul | |||||||
| #[derive(Deserialize, Debug)] | #[derive(Deserialize, Debug)] | ||||||
| #[allow(non_snake_case)] | #[allow(non_snake_case)] | ||||||
| struct CipherData { | struct CipherData { | ||||||
|  |     // Id is optional as it is included only in bulk share | ||||||
|  |     Id: Option<String>, | ||||||
|     // Folder id is not included in import |     // Folder id is not included in import | ||||||
|     FolderId: Option<String>, |     FolderId: Option<String>, | ||||||
|     // TODO: Some of these might appear all the time, no need for Option |     // TODO: Some of these might appear all the time, no need for Option | ||||||
| @@ -332,6 +334,65 @@ struct ShareCipherData { | |||||||
| fn post_cipher_share(uuid: String, data: JsonUpcase<ShareCipherData>, headers: Headers, conn: DbConn) -> JsonResult { | fn post_cipher_share(uuid: String, data: JsonUpcase<ShareCipherData>, headers: Headers, conn: DbConn) -> JsonResult { | ||||||
|     let data: ShareCipherData = data.into_inner().data; |     let data: ShareCipherData = data.into_inner().data; | ||||||
|  |  | ||||||
|  |     share_cipher_by_uuid(&uuid, data, &headers, &conn) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[put("/ciphers/<uuid>/share", data = "<data>")] | ||||||
|  | fn put_cipher_share(uuid: String, data: JsonUpcase<ShareCipherData>, headers: Headers, conn: DbConn) -> JsonResult { | ||||||
|  |     let data: ShareCipherData = data.into_inner().data; | ||||||
|  |  | ||||||
|  |     share_cipher_by_uuid(&uuid, data, &headers, &conn) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[derive(Deserialize)] | ||||||
|  | #[allow(non_snake_case)] | ||||||
|  | struct ShareSelectedCipherData { | ||||||
|  |     Ciphers: Vec<CipherData>, | ||||||
|  |     CollectionIds: Vec<String> | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #[put("/ciphers/share", data = "<data>")] | ||||||
|  | fn put_cipher_share_seleted(data: JsonUpcase<ShareSelectedCipherData>, headers: Headers, conn: DbConn) -> EmptyResult { | ||||||
|  |     let mut data: ShareSelectedCipherData = data.into_inner().data; | ||||||
|  |     let mut cipher_ids: Vec<String> = Vec::new(); | ||||||
|  |  | ||||||
|  |     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()), | ||||||
|  |             None => err!("Request missing ids field") | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     let attachments = Attachment::find_by_ciphers(cipher_ids, &conn); | ||||||
|  |      | ||||||
|  |     if attachments.len() > 0 { | ||||||
|  |         err!("Ciphers should not have any attachments.") | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     while let Some(cipher) = data.Ciphers.pop() { | ||||||
|  |         let mut shared_cipher_data = ShareCipherData { | ||||||
|  |             Cipher: cipher, | ||||||
|  |             CollectionIds: data.CollectionIds.clone() | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         match shared_cipher_data.Cipher.Id.take() { | ||||||
|  |             Some(id) => share_cipher_by_uuid(&id, shared_cipher_data , &headers, &conn)?, | ||||||
|  |             None => err!("Request missing ids field") | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | fn share_cipher_by_uuid(uuid: &str, data: ShareCipherData, headers: &Headers, conn: &DbConn) -> JsonResult { | ||||||
|     let mut cipher = match Cipher::find_by_uuid(&uuid, &conn) { |     let mut cipher = match Cipher::find_by_uuid(&uuid, &conn) { | ||||||
|         Some(cipher) => { |         Some(cipher) => { | ||||||
|             if cipher.is_write_accessible_to_user(&headers.user.uuid, &conn) { |             if cipher.is_write_accessible_to_user(&headers.user.uuid, &conn) { | ||||||
| @@ -365,11 +426,6 @@ fn post_cipher_share(uuid: String, data: JsonUpcase<ShareCipherData>, headers: H | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[put("/ciphers/<uuid>/share", data = "<data>")] |  | ||||||
| fn put_cipher_share(uuid: String, data: JsonUpcase<ShareCipherData>, headers: Headers, conn: DbConn) -> JsonResult { |  | ||||||
|     post_cipher_share(uuid, data, headers, conn) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #[post("/ciphers/<uuid>/attachment", format = "multipart/form-data", data = "<data>")] | #[post("/ciphers/<uuid>/attachment", format = "multipart/form-data", data = "<data>")] | ||||||
| fn post_attachment(uuid: String, data: Data, content_type: &ContentType, headers: Headers, conn: DbConn) -> JsonResult { | fn post_attachment(uuid: String, data: Data, content_type: &ContentType, headers: Headers, conn: DbConn) -> JsonResult { | ||||||
|     let cipher = match Cipher::find_by_uuid(&uuid, &conn) { |     let cipher = match Cipher::find_by_uuid(&uuid, &conn) { | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ pub fn routes() -> Vec<Route> { | |||||||
|         post_cipher_admin, |         post_cipher_admin, | ||||||
|         post_cipher_share, |         post_cipher_share, | ||||||
|         put_cipher_share, |         put_cipher_share, | ||||||
|  |         put_cipher_share_seleted, | ||||||
|         post_cipher, |         post_cipher, | ||||||
|         put_cipher, |         put_cipher, | ||||||
|         delete_cipher_post, |         delete_cipher_post, | ||||||
|   | |||||||
| @@ -111,4 +111,10 @@ impl Attachment { | |||||||
|             .filter(attachments::cipher_uuid.eq(cipher_uuid)) |             .filter(attachments::cipher_uuid.eq(cipher_uuid)) | ||||||
|             .load::<Self>(&**conn).expect("Error loading attachments") |             .load::<Self>(&**conn).expect("Error loading attachments") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     pub fn find_by_ciphers(cipher_uuids: Vec<String>, conn: &DbConn) -> Vec<Self> { | ||||||
|  |         attachments::table | ||||||
|  |             .filter(attachments::cipher_uuid.eq_any(cipher_uuids)) | ||||||
|  |             .load::<Self>(&**conn).expect("Error loading attachments") | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user