From 3cf67e0b8ddc8d4f00dc122de511cbff6b650d58 Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Sat, 18 Mar 2023 21:13:06 +0100 Subject: [PATCH 1/3] add endpoint to bulk delete groups --- src/api/core/organizations.rs | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 9c46617a..172c7f90 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -81,6 +81,7 @@ pub fn routes() -> Vec { get_group_details, delete_group, post_delete_group, + bulk_delete_groups, get_group_users, put_group_users, get_user_groups, @@ -2363,17 +2364,21 @@ async fn get_group_details(_org_id: String, group_id: String, _headers: AdminHea } #[post("/organizations//groups//delete")] -async fn post_delete_group(org_id: String, group_id: String, headers: AdminHeaders, conn: DbConn) -> EmptyResult { - delete_group(org_id, group_id, headers, conn).await +async fn post_delete_group(org_id: String, group_id: String, headers: AdminHeaders, mut conn: DbConn) -> EmptyResult { + _delete_group(org_id, group_id, &headers, &mut conn).await } #[delete("/organizations//groups/")] async fn delete_group(org_id: String, group_id: String, headers: AdminHeaders, mut conn: DbConn) -> EmptyResult { + _delete_group(org_id, group_id, &headers, &mut conn).await +} + +async fn _delete_group(org_id: String, group_id: String, headers: &AdminHeaders, conn: &mut DbConn) -> EmptyResult { if !CONFIG.org_groups_enabled() { err!("Group support is disabled"); } - let group = match Group::find_by_uuid(&group_id, &mut conn).await { + let group = match Group::find_by_uuid(&group_id, conn).await { Some(group) => group, _ => err!("Group not found"), }; @@ -2385,11 +2390,30 @@ async fn delete_group(org_id: String, group_id: String, headers: AdminHeaders, m headers.user.uuid.clone(), headers.device.atype, &headers.ip.ip, - &mut conn, + conn, ) .await; - group.delete(&mut conn).await + group.delete(conn).await +} + +#[delete("/organizations//groups", data = "")] +async fn bulk_delete_groups( + org_id: String, + data: JsonUpcase, + headers: AdminHeaders, + mut conn: DbConn, +) -> EmptyResult { + if !CONFIG.org_groups_enabled() { + err!("Group support is disabled"); + } + + let data: OrgBulkIds = data.into_inner().data; + + for group_id in data.Ids { + _delete_group(org_id.clone(), group_id, &headers, &mut conn).await? + } + Ok(()) } #[get("/organizations/<_org_id>/groups/")] From 56cad93e0fecd2d42a321e761c2124d2c64d0847 Mon Sep 17 00:00:00 2001 From: Stefan Melmuk Date: Sat, 18 Mar 2023 20:52:55 +0100 Subject: [PATCH 2/3] add endpoint to bulk delete collections --- src/api/core/organizations.rs | 81 +++++++++++++++++++++++++---------- src/auth.rs | 40 +++++++++++++---- 2 files changed, 91 insertions(+), 30 deletions(-) diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 172c7f90..556da3dd 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -39,6 +39,7 @@ pub fn routes() -> Vec { put_organization_collection_update, delete_organization_collection, post_organization_collection_delete, + bulk_delete_organization_collections, get_org_details, get_org_users, send_invite, @@ -538,6 +539,34 @@ async fn post_organization_collection_delete_user( delete_organization_collection_user(org_id, col_id, org_user_id, headers, conn).await } +async fn _delete_organization_collection( + org_id: &str, + col_id: &str, + headers: &ManagerHeaders, + conn: &mut DbConn, +) -> EmptyResult { + match Collection::find_by_uuid(col_id, conn).await { + None => err!("Collection not found"), + Some(collection) => { + if collection.org_uuid == org_id { + log_event( + EventType::CollectionDeleted as i32, + &collection.uuid, + org_id.to_string(), + headers.user.uuid.clone(), + headers.device.atype, + &headers.ip.ip, + conn, + ) + .await; + collection.delete(conn).await + } else { + err!("Collection and Organization id do not match") + } + } + } +} + #[delete("/organizations//collections/")] async fn delete_organization_collection( org_id: String, @@ -545,26 +574,7 @@ async fn delete_organization_collection( headers: ManagerHeaders, mut conn: DbConn, ) -> EmptyResult { - match Collection::find_by_uuid(&col_id, &mut conn).await { - None => err!("Collection not found"), - Some(collection) => { - if collection.org_uuid == org_id { - log_event( - EventType::CollectionDeleted as i32, - &collection.uuid, - org_id, - headers.user.uuid.clone(), - headers.device.atype, - &headers.ip.ip, - &mut conn, - ) - .await; - collection.delete(&mut conn).await - } else { - err!("Collection and Organization id do not match") - } - } - } + _delete_organization_collection(&org_id, &col_id, &headers, &mut conn).await } #[derive(Deserialize, Debug)] @@ -580,9 +590,36 @@ async fn post_organization_collection_delete( col_id: String, headers: ManagerHeaders, _data: JsonUpcase, - conn: DbConn, + mut conn: DbConn, ) -> EmptyResult { - delete_organization_collection(org_id, col_id, headers, conn).await + _delete_organization_collection(&org_id, &col_id, &headers, &mut conn).await +} + +#[derive(Deserialize, Debug)] +#[allow(non_snake_case)] +struct BulkCollectionIds { + Ids: Vec, + OrganizationId: String, +} + +#[delete("/organizations//collections", data = "")] +async fn bulk_delete_organization_collections( + org_id: &str, + headers: ManagerHeadersLoose, + data: JsonUpcase, + mut conn: DbConn, +) -> EmptyResult { + let data: BulkCollectionIds = data.into_inner().data; + assert!(org_id == data.OrganizationId); + + let collections = data.Ids; + + let headers = ManagerHeaders::from_loose(headers, &collections, &mut conn).await?; + + for col_id in collections { + _delete_organization_collection(org_id, &col_id, &headers, &mut conn).await? + } + Ok(()) } #[get("/organizations//collections//details")] diff --git a/src/auth.rs b/src/auth.rs index e5779dd6..b1b68af5 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -598,14 +598,7 @@ impl<'r> FromRequest<'r> for ManagerHeaders { _ => err_handler!("Error getting DB"), }; - if !headers.org_user.has_full_access() - && !Collection::has_access_by_collection_and_user_uuid( - &col_id, - &headers.org_user.user_uuid, - &mut conn, - ) - .await - { + if !can_access_collection(&headers.org_user, &col_id, &mut conn).await { err_handler!("The current user isn't a manager for this collection") } } @@ -642,6 +635,7 @@ pub struct ManagerHeadersLoose { pub host: String, pub device: Device, pub user: User, + pub org_user: UserOrganization, pub org_user_type: UserOrgType, pub ip: ClientIp, } @@ -657,6 +651,7 @@ impl<'r> FromRequest<'r> for ManagerHeadersLoose { host: headers.host, device: headers.device, user: headers.user, + org_user: headers.org_user, org_user_type: headers.org_user_type, ip: headers.ip, }) @@ -676,6 +671,35 @@ impl From for Headers { } } } +async fn can_access_collection(org_user: &UserOrganization, col_id: &str, conn: &mut DbConn) -> bool { + org_user.has_full_access() + || Collection::has_access_by_collection_and_user_uuid(col_id, &org_user.user_uuid, conn).await +} + +impl ManagerHeaders { + pub async fn from_loose( + h: ManagerHeadersLoose, + collections: &Vec, + conn: &mut DbConn, + ) -> Result { + for col_id in collections { + if uuid::Uuid::parse_str(col_id).is_err() { + err!("Collection Id is malformed!"); + } + if !can_access_collection(&h.org_user, col_id, conn).await { + err!("You don't have access to all collections!"); + } + } + + Ok(ManagerHeaders { + host: h.host, + device: h.device, + user: h.user, + org_user_type: h.org_user_type, + ip: h.ip, + }) + } +} pub struct OwnerHeaders { pub host: String, From ed8091a994a97747b8a0b13913c5a30ddd1d4c82 Mon Sep 17 00:00:00 2001 From: Stefan Melmuk <509385+stefan0xC@users.noreply.github.com> Date: Wed, 22 Mar 2023 21:45:57 +0100 Subject: [PATCH 3/3] don't use `assert()` in production code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniel GarcĂ­a --- src/api/core/organizations.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 556da3dd..cac71615 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -610,7 +610,9 @@ async fn bulk_delete_organization_collections( mut conn: DbConn, ) -> EmptyResult { let data: BulkCollectionIds = data.into_inner().data; - assert!(org_id == data.OrganizationId); + if org_id != data.OrganizationId { + err!("OrganizationId mismatch"); + } let collections = data.Ids;