diff options
Diffstat (limited to 'src/api/core')
-rw-r--r-- | src/api/core/accounts.rs | 96 | ||||
-rw-r--r-- | src/api/core/ciphers.rs | 104 | ||||
-rw-r--r-- | src/api/core/emergency_access.rs | 170 | ||||
-rw-r--r-- | src/api/core/folders.rs | 30 | ||||
-rw-r--r-- | src/api/core/organizations.rs | 296 | ||||
-rw-r--r-- | src/api/core/public.rs | 15 | ||||
-rw-r--r-- | src/api/core/sends.rs | 69 | ||||
-rw-r--r-- | src/api/core/two_factor/authenticator.rs | 5 | ||||
-rw-r--r-- | src/api/core/two_factor/duo.rs | 15 | ||||
-rw-r--r-- | src/api/core/two_factor/email.rs | 17 | ||||
-rw-r--r-- | src/api/core/two_factor/mod.rs | 5 | ||||
-rw-r--r-- | src/api/core/two_factor/webauthn.rs | 15 |
12 files changed, 330 insertions, 507 deletions
diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index 87e44529..d95a50b8 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -574,9 +574,8 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn, // Skip `null` folder id entries. // See: https://github.com/bitwarden/clients/issues/8453 if let Some(folder_id) = folder_data.id { - let saved_folder = match existing_folders.iter_mut().find(|f| f.uuid == folder_id) { - Some(folder) => folder, - None => err!("Folder doesn't exist"), + let Some(saved_folder) = existing_folders.iter_mut().find(|f| f.uuid == folder_id) else { + err!("Folder doesn't exist") }; saved_folder.name = folder_data.name; @@ -586,11 +585,11 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn, // Update emergency access data for emergency_access_data in data.emergency_access_keys { - let saved_emergency_access = - match existing_emergency_access.iter_mut().find(|ea| ea.uuid == emergency_access_data.id) { - Some(emergency_access) => emergency_access, - None => err!("Emergency access doesn't exist or is not owned by the user"), - }; + let Some(saved_emergency_access) = + existing_emergency_access.iter_mut().find(|ea| ea.uuid == emergency_access_data.id) + else { + err!("Emergency access doesn't exist or is not owned by the user") + }; saved_emergency_access.key_encrypted = Some(emergency_access_data.key_encrypted); saved_emergency_access.save(&mut conn).await? @@ -598,10 +597,10 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn, // Update reset password data for reset_password_data in data.reset_password_keys { - let user_org = match existing_user_orgs.iter_mut().find(|uo| uo.org_uuid == reset_password_data.organization_id) - { - Some(reset_password) => reset_password, - None => err!("Reset password doesn't exist"), + let Some(user_org) = + existing_user_orgs.iter_mut().find(|uo| uo.org_uuid == reset_password_data.organization_id) + else { + err!("Reset password doesn't exist") }; user_org.reset_password_key = Some(reset_password_data.reset_password_key); @@ -610,9 +609,8 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn, // Update send data for send_data in data.sends { - let send = match existing_sends.iter_mut().find(|s| &s.uuid == send_data.id.as_ref().unwrap()) { - Some(send) => send, - None => err!("Send doesn't exist"), + let Some(send) = existing_sends.iter_mut().find(|s| &s.uuid == send_data.id.as_ref().unwrap()) else { + err!("Send doesn't exist") }; update_send_from_data(send, send_data, &headers, &mut conn, &nt, UpdateType::None).await?; @@ -623,9 +621,9 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn, for cipher_data in data.ciphers { if cipher_data.organization_id.is_none() { - let saved_cipher = match existing_ciphers.iter_mut().find(|c| &c.uuid == cipher_data.id.as_ref().unwrap()) { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(saved_cipher) = existing_ciphers.iter_mut().find(|c| &c.uuid == cipher_data.id.as_ref().unwrap()) + else { + err!("Cipher doesn't exist") }; // Prevent triggering cipher updates via WebSockets by settings UpdateType::None @@ -802,14 +800,12 @@ struct VerifyEmailTokenData { async fn post_verify_email_token(data: Json<VerifyEmailTokenData>, mut conn: DbConn) -> EmptyResult { let data: VerifyEmailTokenData = data.into_inner(); - let mut user = match User::find_by_uuid(&data.user_id, &mut conn).await { - Some(user) => user, - None => err!("User doesn't exist"), + let Some(mut user) = User::find_by_uuid(&data.user_id, &mut conn).await else { + err!("User doesn't exist") }; - let claims = match decode_verify_email(&data.token) { - Ok(claims) => claims, - Err(_) => err!("Invalid claim"), + let Ok(claims) = decode_verify_email(&data.token) else { + err!("Invalid claim") }; if claims.sub != user.uuid { err!("Invalid claim"); @@ -861,15 +857,14 @@ struct DeleteRecoverTokenData { async fn post_delete_recover_token(data: Json<DeleteRecoverTokenData>, mut conn: DbConn) -> EmptyResult { let data: DeleteRecoverTokenData = data.into_inner(); - let user = match User::find_by_uuid(&data.user_id, &mut conn).await { - Some(user) => user, - None => err!("User doesn't exist"), + let Ok(claims) = decode_delete(&data.token) else { + err!("Invalid claim") }; - let claims = match decode_delete(&data.token) { - Ok(claims) => claims, - Err(_) => err!("Invalid claim"), + let Some(user) = User::find_by_uuid(&data.user_id, &mut conn).await else { + err!("User doesn't exist") }; + if claims.sub != user.uuid { err!("Invalid claim"); } @@ -1041,11 +1036,8 @@ impl<'r> FromRequest<'r> for KnownDevice { async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> { let email = if let Some(email_b64) = req.headers().get_one("X-Request-Email") { - let email_bytes = match data_encoding::BASE64URL_NOPAD.decode(email_b64.as_bytes()) { - Ok(bytes) => bytes, - Err(_) => { - return Outcome::Error((Status::BadRequest, "X-Request-Email value failed to decode as base64url")); - } + let Ok(email_bytes) = data_encoding::BASE64URL_NOPAD.decode(email_b64.as_bytes()) else { + return Outcome::Error((Status::BadRequest, "X-Request-Email value failed to decode as base64url")); }; match String::from_utf8(email_bytes) { Ok(email) => email, @@ -1086,9 +1078,9 @@ async fn put_device_token(uuid: &str, data: Json<PushToken>, headers: Headers, m let data = data.into_inner(); let token = data.push_token; - let mut device = match Device::find_by_uuid_and_user(&headers.device.uuid, &headers.user.uuid, &mut conn).await { - Some(device) => device, - None => err!(format!("Error: device {uuid} should be present before a token can be assigned")), + let Some(mut device) = Device::find_by_uuid_and_user(&headers.device.uuid, &headers.user.uuid, &mut conn).await + else { + err!(format!("Error: device {uuid} should be present before a token can be assigned")) }; // if the device already has been registered @@ -1159,9 +1151,8 @@ async fn post_auth_request( ) -> JsonResult { let data = data.into_inner(); - let user = match User::find_by_mail(&data.email, &mut conn).await { - Some(user) => user, - None => err!("AuthRequest doesn't exist", "User not found"), + let Some(user) = User::find_by_mail(&data.email, &mut conn).await else { + err!("AuthRequest doesn't exist", "User not found") }; // Validate device uuid and type @@ -1199,15 +1190,10 @@ async fn post_auth_request( #[get("/auth-requests/<uuid>")] async fn get_auth_request(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult { - let auth_request = match AuthRequest::find_by_uuid(uuid, &mut conn).await { - Some(auth_request) => auth_request, - None => err!("AuthRequest doesn't exist", "Record not found"), + let Some(auth_request) = AuthRequest::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else { + err!("AuthRequest doesn't exist", "Record not found or user uuid does not match") }; - if headers.user.uuid != auth_request.user_uuid { - err!("AuthRequest doesn't exist", "User uuid's do not match") - } - let response_date_utc = auth_request.response_date.map(|response_date| format_date(&response_date)); Ok(Json(json!({ @@ -1244,15 +1230,10 @@ async fn put_auth_request( nt: Notify<'_>, ) -> JsonResult { let data = data.into_inner(); - let mut auth_request: AuthRequest = match AuthRequest::find_by_uuid(uuid, &mut conn).await { - Some(auth_request) => auth_request, - None => err!("AuthRequest doesn't exist", "Record not found"), + let Some(mut auth_request) = AuthRequest::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else { + err!("AuthRequest doesn't exist", "Record not found or user uuid does not match") }; - if headers.user.uuid != auth_request.user_uuid { - err!("AuthRequest doesn't exist", "User uuid's do not match") - } - if auth_request.approved.is_some() { err!("An authentication request with the same device already exists") } @@ -1297,9 +1278,8 @@ async fn get_auth_request_response( client_headers: ClientHeaders, mut conn: DbConn, ) -> JsonResult { - let auth_request = match AuthRequest::find_by_uuid(uuid, &mut conn).await { - Some(auth_request) => auth_request, - None => err!("AuthRequest doesn't exist", "User not found"), + let Some(auth_request) = AuthRequest::find_by_uuid(uuid, &mut conn).await else { + err!("AuthRequest doesn't exist", "User not found") }; if auth_request.device_type != client_headers.device_type diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index 46d65b53..136b890a 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -193,9 +193,8 @@ async fn get_ciphers(headers: Headers, mut conn: DbConn) -> Json<Value> { #[get("/ciphers/<uuid>")] async fn get_cipher(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult { - let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await { @@ -429,14 +428,9 @@ pub async fn update_cipher_from_data( cipher.user_uuid = Some(headers.user.uuid.clone()); } - if let Some(ref folder_id) = data.folder_id { - match Folder::find_by_uuid(folder_id, conn).await { - Some(folder) => { - if folder.user_uuid != headers.user.uuid { - err!("Folder is not owned by user") - } - } - None => err!("Folder doesn't exist"), + if let Some(ref folder_uuid) = data.folder_id { + if Folder::find_by_uuid_and_user(folder_uuid, &headers.user.uuid, conn).await.is_none() { + err!("Invalid folder", "Folder does not exist or belongs to another user"); } } @@ -661,9 +655,8 @@ async fn put_cipher( ) -> JsonResult { let data: CipherData = data.into_inner(); - let mut cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(mut cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else { + err!("Cipher doesn't exist") }; // TODO: Check if only the folder ID or favorite status is being changed. @@ -695,19 +688,13 @@ async fn put_cipher_partial( ) -> JsonResult { let data: PartialCipherData = data.into_inner(); - let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else { + err!("Cipher doesn't exist") }; - if let Some(ref folder_id) = data.folder_id { - match Folder::find_by_uuid(folder_id, &mut conn).await { - Some(folder) => { - if folder.user_uuid != headers.user.uuid { - err!("Folder is not owned by user") - } - } - None => err!("Folder doesn't exist"), + if let Some(ref folder_uuid) = data.folder_id { + if Folder::find_by_uuid_and_user(folder_uuid, &headers.user.uuid, &mut conn).await.is_none() { + err!("Invalid folder", "Folder does not exist or belongs to another user"); } } @@ -774,9 +761,8 @@ async fn post_collections_update( ) -> JsonResult { let data: CollectionsAdminData = data.into_inner(); - let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { @@ -788,7 +774,8 @@ async fn post_collections_update( HashSet::<String>::from_iter(cipher.get_collections(headers.user.uuid.clone(), &mut conn).await); for collection in posted_collections.symmetric_difference(¤t_collections) { - match Collection::find_by_uuid(collection, &mut conn).await { + match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &mut conn).await + { None => err!("Invalid collection ID provided"), Some(collection) => { if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await { @@ -851,9 +838,8 @@ async fn post_collections_admin( ) -> EmptyResult { let data: CollectionsAdminData = data.into_inner(); - let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { @@ -865,7 +851,8 @@ async fn post_collections_admin( HashSet::<String>::from_iter(cipher.get_admin_collections(headers.user.uuid.clone(), &mut conn).await); for collection in posted_collections.symmetric_difference(¤t_collections) { - match Collection::find_by_uuid(collection, &mut conn).await { + match Collection::find_by_uuid_and_org(collection, cipher.organization_uuid.as_ref().unwrap(), &mut conn).await + { None => err!("Invalid collection ID provided"), Some(collection) => { if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await { @@ -1043,9 +1030,8 @@ async fn share_cipher_by_uuid( /// redirects to the same location as before the v2 API. #[get("/ciphers/<uuid>/attachment/<attachment_id>")] async fn get_attachment(uuid: &str, attachment_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult { - let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await { @@ -1084,9 +1070,8 @@ async fn post_attachment_v2( headers: Headers, mut conn: DbConn, ) -> JsonResult { - let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { @@ -1150,9 +1135,8 @@ async fn save_attachment( err!("Attachment size can't be negative") } - let cipher = match Cipher::find_by_uuid(cipher_uuid, &mut conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(cipher) = Cipher::find_by_uuid(cipher_uuid, &mut conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { @@ -1545,21 +1529,15 @@ async fn move_cipher_selected( let data = data.into_inner(); let user_uuid = headers.user.uuid; - if let Some(ref folder_id) = data.folder_id { - match Folder::find_by_uuid(folder_id, &mut conn).await { - Some(folder) => { - if folder.user_uuid != user_uuid { - err!("Folder is not owned by user") - } - } - None => err!("Folder doesn't exist"), + if let Some(ref folder_uuid) = data.folder_id { + if Folder::find_by_uuid_and_user(folder_uuid, &user_uuid, &mut conn).await.is_none() { + err!("Invalid folder", "Folder does not exist or belongs to another user"); } } for uuid in data.ids { - let cipher = match Cipher::find_by_uuid(&uuid, &mut conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_accessible_to_user(&user_uuid, &mut conn).await { @@ -1667,9 +1645,8 @@ async fn _delete_cipher_by_uuid( soft_delete: bool, nt: &Notify<'_>, ) -> EmptyResult { - let mut cipher = match Cipher::find_by_uuid(uuid, conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(mut cipher) = Cipher::find_by_uuid(uuid, conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await { @@ -1739,9 +1716,8 @@ async fn _delete_multiple_ciphers( } async fn _restore_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &mut DbConn, nt: &Notify<'_>) -> JsonResult { - let mut cipher = match Cipher::find_by_uuid(uuid, conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(mut cipher) = Cipher::find_by_uuid(uuid, conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await { @@ -1807,18 +1783,16 @@ async fn _delete_cipher_attachment_by_id( conn: &mut DbConn, nt: &Notify<'_>, ) -> EmptyResult { - let attachment = match Attachment::find_by_id(attachment_id, conn).await { - Some(attachment) => attachment, - None => err!("Attachment doesn't exist"), + let Some(attachment) = Attachment::find_by_id(attachment_id, conn).await else { + err!("Attachment doesn't exist") }; if attachment.cipher_uuid != uuid { err!("Attachment from other cipher") } - let cipher = match Cipher::find_by_uuid(uuid, conn).await { - Some(cipher) => cipher, - None => err!("Cipher doesn't exist"), + let Some(cipher) = Cipher::find_by_uuid(uuid, conn).await else { + err!("Cipher doesn't exist") }; if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await { diff --git a/src/api/core/emergency_access.rs b/src/api/core/emergency_access.rs index 1c29b774..8ed9e87a 100644 --- a/src/api/core/emergency_access.rs +++ b/src/api/core/emergency_access.rs @@ -137,11 +137,11 @@ async fn post_emergency_access( let data: EmergencyAccessUpdateData = data.into_inner(); - let mut emergency_access = - match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await { - Some(emergency_access) => emergency_access, - None => err!("Emergency access not valid."), - }; + let Some(mut emergency_access) = + EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; let new_type = match EmergencyAccessType::from_str(&data.r#type.into_string()) { Some(new_type) => new_type as i32, @@ -284,24 +284,22 @@ async fn send_invite(data: Json<EmergencyAccessInviteData>, headers: Headers, mu async fn resend_invite(emer_id: &str, headers: Headers, mut conn: DbConn) -> EmptyResult { check_emergency_access_enabled()?; - let mut emergency_access = - match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(mut emergency_access) = + EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; if emergency_access.status != EmergencyAccessStatus::Invited as i32 { err!("The grantee user is already accepted or confirmed to the organization"); } - let email = match emergency_access.email.clone() { - Some(email) => email, - None => err!("Email not valid."), + let Some(email) = emergency_access.email.clone() else { + err!("Email not valid.") }; - let grantee_user = match User::find_by_mail(&email, &mut conn).await { - Some(user) => user, - None => err!("Grantee user not found."), + let Some(grantee_user) = User::find_by_mail(&email, &mut conn).await else { + err!("Grantee user not found.") }; let grantor_user = headers.user; @@ -356,16 +354,15 @@ async fn accept_invite(emer_id: &str, data: Json<AcceptData>, headers: Headers, // We need to search for the uuid in combination with the email, since we do not yet store the uuid of the grantee in the database. // The uuid of the grantee gets stored once accepted. - let mut emergency_access = - match EmergencyAccess::find_by_uuid_and_grantee_email(emer_id, &headers.user.email, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(mut emergency_access) = + EmergencyAccess::find_by_uuid_and_grantee_email(emer_id, &headers.user.email, &mut conn).await + else { + err!("Emergency access not valid.") + }; // get grantor user to send Accepted email - let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantor user not found."), + let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else { + err!("Grantor user not found.") }; if emer_id == claims.emer_id @@ -403,11 +400,11 @@ async fn confirm_emergency_access( let data: ConfirmData = data.into_inner(); let key = data.key; - let mut emergency_access = - match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &confirming_user.uuid, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(mut emergency_access) = + EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &confirming_user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; if emergency_access.status != EmergencyAccessStatus::Accepted as i32 || emergency_access.grantor_uuid != confirming_user.uuid @@ -415,15 +412,13 @@ async fn confirm_emergency_access( err!("Emergency access not valid.") } - let grantor_user = match User::find_by_uuid(&confirming_user.uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantor user not found."), + let Some(grantor_user) = User::find_by_uuid(&confirming_user.uuid, &mut conn).await else { + err!("Grantor user not found.") }; if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() { - let grantee_user = match User::find_by_uuid(grantee_uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantee user not found."), + let Some(grantee_user) = User::find_by_uuid(grantee_uuid, &mut conn).await else { + err!("Grantee user not found.") }; emergency_access.status = EmergencyAccessStatus::Confirmed as i32; @@ -450,19 +445,18 @@ async fn initiate_emergency_access(emer_id: &str, headers: Headers, mut conn: Db check_emergency_access_enabled()?; let initiating_user = headers.user; - let mut emergency_access = - match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &initiating_user.uuid, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(mut emergency_access) = + EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &initiating_user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; if emergency_access.status != EmergencyAccessStatus::Confirmed as i32 { err!("Emergency access not valid.") } - let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantor user not found."), + let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else { + err!("Grantor user not found.") }; let now = Utc::now().naive_utc(); @@ -488,25 +482,23 @@ async fn initiate_emergency_access(emer_id: &str, headers: Headers, mut conn: Db async fn approve_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult { check_emergency_access_enabled()?; - let mut emergency_access = - match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(mut emergency_access) = + EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32 { err!("Emergency access not valid.") } - let grantor_user = match User::find_by_uuid(&headers.user.uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantor user not found."), + let Some(grantor_user) = User::find_by_uuid(&headers.user.uuid, &mut conn).await else { + err!("Grantor user not found.") }; if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() { - let grantee_user = match User::find_by_uuid(grantee_uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantee user not found."), + let Some(grantee_user) = User::find_by_uuid(grantee_uuid, &mut conn).await else { + err!("Grantee user not found.") }; emergency_access.status = EmergencyAccessStatus::RecoveryApproved as i32; @@ -525,11 +517,11 @@ async fn approve_emergency_access(emer_id: &str, headers: Headers, mut conn: DbC async fn reject_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult { check_emergency_access_enabled()?; - let mut emergency_access = - match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(mut emergency_access) = + EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32 && emergency_access.status != EmergencyAccessStatus::RecoveryApproved as i32 @@ -538,9 +530,8 @@ async fn reject_emergency_access(emer_id: &str, headers: Headers, mut conn: DbCo } if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() { - let grantee_user = match User::find_by_uuid(grantee_uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantee user not found."), + let Some(grantee_user) = User::find_by_uuid(grantee_uuid, &mut conn).await else { + err!("Grantee user not found.") }; emergency_access.status = EmergencyAccessStatus::Confirmed as i32; @@ -563,11 +554,11 @@ async fn reject_emergency_access(emer_id: &str, headers: Headers, mut conn: DbCo async fn view_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult { check_emergency_access_enabled()?; - let emergency_access = - match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &headers.user.uuid, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(emergency_access) = + EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &headers.user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; if !is_valid_request(&emergency_access, &headers.user.uuid, EmergencyAccessType::View) { err!("Emergency access not valid.") @@ -602,19 +593,18 @@ async fn takeover_emergency_access(emer_id: &str, headers: Headers, mut conn: Db check_emergency_access_enabled()?; let requesting_user = headers.user; - let emergency_access = - match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(emergency_access) = + EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) { err!("Emergency access not valid.") } - let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantor user not found."), + let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else { + err!("Grantor user not found.") }; let result = json!({ @@ -650,19 +640,18 @@ async fn password_emergency_access( //let key = &data.Key; let requesting_user = headers.user; - let emergency_access = - match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(emergency_access) = + EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) { err!("Emergency access not valid.") } - let mut grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantor user not found."), + let Some(mut grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else { + err!("Grantor user not found.") }; // change grantor_user password @@ -686,19 +675,18 @@ async fn password_emergency_access( #[get("/emergency-access/<emer_id>/policies")] async fn policies_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult { let requesting_user = headers.user; - let emergency_access = - match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await { - Some(emer) => emer, - None => err!("Emergency access not valid."), - }; + let Some(emergency_access) = + EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await + else { + err!("Emergency access not valid.") + }; if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) { err!("Emergency access not valid.") } - let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { - Some(user) => user, - None => err!("Grantor user not found."), + let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else { + err!("Grantor user not found.") }; let policies = OrgPolicy::find_confirmed_by_user(&grantor_user.uuid, &mut conn); diff --git a/src/api/core/folders.rs b/src/api/core/folders.rs index 9766d7a1..3daa2a06 100644 --- a/src/api/core/folders.rs +++ b/src/api/core/folders.rs @@ -25,16 +25,10 @@ async fn get_folders(headers: Headers, mut conn: DbConn) -> Json<Value> { #[get("/folders/<uuid>")] async fn get_folder(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult { - let folder = match Folder::find_by_uuid(uuid, &mut conn).await { - Some(folder) => folder, - _ => err!("Invalid folder"), - }; - - if folder.user_uuid != headers.user.uuid { - err!("Folder belongs to another user") + match Folder::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await { + Some(folder) => Ok(Json(folder.to_json())), + _ => err!("Invalid folder", "Folder does not exist or belongs to another user"), } - - Ok(Json(folder.to_json())) } #[derive(Deserialize)] @@ -71,15 +65,10 @@ async fn put_folder( ) -> JsonResult { let data: FolderData = data.into_inner(); - let mut folder = match Folder::find_by_uuid(uuid, &mut conn).await { - Some(folder) => folder, - _ => err!("Invalid folder"), + let Some(mut folder) = Folder::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else { + err!("Invalid folder", "Folder does not exist or belongs to another user") }; - if folder.user_uuid != headers.user.uuid { - err!("Folder belongs to another user") - } - folder.name = data.name; folder.save(&mut conn).await?; @@ -95,15 +84,10 @@ async fn delete_folder_post(uuid: &str, headers: Headers, conn: DbConn, nt: Noti #[delete("/folders/<uuid>")] async fn delete_folder(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { - let folder = match Folder::find_by_uuid(uuid, &mut conn).await { - Some(folder) => folder, - _ => err!("Invalid folder"), + let Some(folder) = Folder::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else { + err!("Invalid folder", "Folder does not exist or belongs to another user") }; - if folder.user_uuid != headers.user.uuid { - err!("Folder belongs to another user") - } - // Delete the actual folder entry folder.delete(&mut conn).await?; diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 2bff64b8..f3158536 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -267,9 +267,8 @@ async fn post_organization( ) -> JsonResult { let data: OrganizationUpdateData = data.into_inner(); - let mut org = match Organization::find_by_uuid(org_id, &mut conn).await { - Some(organization) => organization, - None => err!("Can't find organization details"), + let Some(mut org) = Organization::find_by_uuid(org_id, &mut conn).await else { + err!("Can't find organization details") }; org.name = data.name; @@ -318,9 +317,8 @@ async fn get_org_collections(org_id: &str, _headers: ManagerHeadersLoose, mut co async fn get_org_collections_details(org_id: &str, headers: ManagerHeadersLoose, mut conn: DbConn) -> JsonResult { let mut data = Vec::new(); - let user_org = match UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await { - Some(u) => u, - None => err!("User is not part of organization"), + let Some(user_org) = UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await else { + err!("User is not part of organization") }; // get all collection memberships for the current organization @@ -387,9 +385,8 @@ async fn post_organization_collections( ) -> JsonResult { let data: NewCollectionData = data.into_inner(); - let org = match Organization::find_by_uuid(org_id, &mut conn).await { - Some(organization) => organization, - None => err!("Can't find organization details"), + let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else { + err!("Can't find organization details") }; let collection = Collection::new(org.uuid, data.name, data.external_id); @@ -413,9 +410,8 @@ async fn post_organization_collections( } for user in data.users { - let org_user = match UserOrganization::find_by_uuid(&user.id, &mut conn).await { - Some(u) => u, - None => err!("User is not part of organization"), + let Some(org_user) = UserOrganization::find_by_uuid_and_org(&user.id, org_id, &mut conn).await else { + err!("User is not part of organization") }; if org_user.access_all { @@ -454,20 +450,14 @@ async fn post_organization_collection_update( ) -> JsonResult { let data: NewCollectionData = data.into_inner(); - let org = match Organization::find_by_uuid(org_id, &mut conn).await { - Some(organization) => organization, - None => err!("Can't find organization details"), + if Organization::find_by_uuid(org_id, &mut conn).await.is_none() { + err!("Can't find organization details") }; - let mut collection = match Collection::find_by_uuid(col_id, &mut conn).await { - Some(collection) => collection, - None => err!("Collection not found"), + let Some(mut collection) = Collection::find_by_uuid_and_org(col_id, org_id, &mut conn).await else { + err!("Collection not found") }; - if collection.org_uuid != org.uuid { - err!("Collection is not owned by organization"); - } - collection.name = data.name; collection.external_id = match data.external_id { Some(external_id) if !external_id.trim().is_empty() => Some(external_id), @@ -498,9 +488,8 @@ async fn post_organization_collection_update( CollectionUser::delete_all_by_collection(col_id, &mut conn).await?; for user in data.users { - let org_user = match UserOrganization::find_by_uuid(&user.id, &mut conn).await { - Some(u) => u, - None => err!("User is not part of organization"), + let Some(org_user) = UserOrganization::find_by_uuid_and_org(&user.id, org_id, &mut conn).await else { + err!("User is not part of organization") }; if org_user.access_all { @@ -521,15 +510,8 @@ async fn delete_organization_collection_user( _headers: AdminHeaders, mut conn: DbConn, ) -> EmptyResult { - let collection = match Collection::find_by_uuid(col_id, &mut conn).await { - None => err!("Collection not found"), - Some(collection) => { - if collection.org_uuid == org_id { - collection - } else { - err!("Collection and Organization id do not match") - } - } + let Some(collection) = Collection::find_by_uuid_and_org(col_id, org_id, &mut conn).await else { + err!("Collection not found", "Collection does not exist or does not belong to this organization") }; match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await { @@ -560,26 +542,20 @@ async fn _delete_organization_collection( 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, - &headers.user.uuid, - headers.device.atype, - &headers.ip.ip, - conn, - ) - .await; - collection.delete(conn).await - } else { - err!("Collection and Organization id do not match") - } - } - } + let Some(collection) = Collection::find_by_uuid_and_org(col_id, org_id, conn).await else { + err!("Collection not found", "Collection does not exist or does not belong to this organization") + }; + log_event( + EventType::CollectionDeleted as i32, + &collection.uuid, + org_id, + &headers.user.uuid, + headers.device.atype, + &headers.ip.ip, + conn, + ) + .await; + collection.delete(conn).await } #[delete("/organizations/<org_id>/collections/<col_id>")] @@ -601,12 +577,11 @@ struct DeleteCollectionData { org_id: String, } -#[post("/organizations/<org_id>/collections/<col_id>/delete", data = "<_data>")] +#[post("/organizations/<org_id>/collections/<col_id>/delete")] async fn post_organization_collection_delete( org_id: &str, col_id: &str, headers: ManagerHeaders, - _data: Json<DeleteCollectionData>, mut conn: DbConn, ) -> EmptyResult { _delete_organization_collection(org_id, col_id, &headers, &mut conn).await @@ -651,9 +626,9 @@ async fn get_org_collection_detail( err!("Collection is not owned by organization") } - let user_org = match UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await { - Some(u) => u, - None => err!("User is not part of organization"), + let Some(user_org) = UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await + else { + err!("User is not part of organization") }; let groups: Vec<Value> = if CONFIG.org_groups_enabled() { @@ -695,9 +670,8 @@ async fn get_org_collection_detail( #[get("/organizations/<org_id>/collections/<coll_id>/users")] async fn get_collection_users(org_id: &str, coll_id: &str, _headers: ManagerHeaders, mut conn: DbConn) -> JsonResult { // Get org and collection, check that collection is from org - let collection = match Collection::find_by_uuid_and_org(coll_id, org_id, &mut conn).await { - None => err!("Collection not found in Organization"), - Some(collection) => collection, + let Some(collection) = Collection::find_by_uuid_and_org(coll_id, org_id, &mut conn).await else { + err!("Collection not found in Organization") }; let mut user_list = Vec::new(); @@ -731,9 +705,8 @@ async fn put_collection_users( // And then add all the received ones (except if the user has access_all) for d in data.iter() { - let user = match UserOrganization::find_by_uuid(&d.id, &mut conn).await { - Some(u) => u, - None => err!("User is not part of organization"), + let Some(user) = UserOrganization::find_by_uuid_and_org(&d.id, org_id, &mut conn).await else { + err!("User is not part of organization") }; if user.access_all { @@ -1007,18 +980,16 @@ async fn reinvite_user(org_id: &str, user_org: &str, headers: AdminHeaders, mut } async fn _reinvite_user(org_id: &str, user_org: &str, invited_by_email: &str, conn: &mut DbConn) -> EmptyResult { - let user_org = match UserOrganization::find_by_uuid(user_org, conn).await { - Some(user_org) => user_org, - None => err!("The user hasn't been invited to the organization."), + let Some(user_org) = UserOrganization::find_by_uuid_and_org(user_org, org_id, conn).await else { + err!("The user hasn't been invited to the organization.") }; if user_org.status != UserOrgStatus::Invited as i32 { err!("The user is already accepted or confirmed to the organization") } - let user = match User::find_by_uuid(&user_org.user_uuid, conn).await { - Some(user) => user, - None => err!("User not found."), + let Some(user) = User::find_by_uuid(&user_org.user_uuid, conn).await else { + err!("User not found.") }; if !CONFIG.invitations_allowed() && user.password_hash.is_empty() { @@ -1059,20 +1030,25 @@ struct AcceptData { reset_password_key: Option<String>, } -#[post("/organizations/<org_id>/users/<_org_user_id>/accept", data = "<data>")] -async fn accept_invite(org_id: &str, _org_user_id: &str, data: Json<AcceptData>, mut conn: DbConn) -> EmptyResult { +#[post("/organizations/<org_id>/users/<org_user_id>/accept", data = "<data>")] +async fn accept_invite(org_id: &str, org_user_id: &str, data: Json<AcceptData>, mut conn: DbConn) -> EmptyResult { // The web-vault passes org_id and org_user_id in the URL, but we are just reading them from the JWT instead let data: AcceptData = data.into_inner(); let claims = decode_invite(&data.token)?; + // If a claim does not have a user_org_id or it does not match the one in from the URI, something is wrong. + match &claims.user_org_id { + Some(ou_id) if ou_id.eq(org_user_id) => {} + _ => err!("Error accepting the invitation", "Claim does not match the org_user_id"), + } + match User::find_by_mail(&claims.email, &mut conn).await { Some(user) => { Invitation::take(&claims.email, &mut conn).await; if let (Some(user_org), Some(org)) = (&claims.user_org_id, &claims.org_id) { - let mut user_org = match UserOrganization::find_by_uuid_and_org(user_org, org, &mut conn).await { - Some(user_org) => user_org, - None => err!("Error accepting the invitation"), + let Some(mut user_org) = UserOrganization::find_by_uuid_and_org(user_org, org, &mut conn).await else { + err!("Error accepting the invitation") }; if user_org.status != UserOrgStatus::Invited as i32 { @@ -1213,9 +1189,8 @@ async fn _confirm_invite( err!("Key or UserId is not set, unable to process request"); } - let mut user_to_confirm = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { - Some(user) => user, - None => err!("The specified user isn't a member of the organization"), + let Some(mut user_to_confirm) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await else { + err!("The specified user isn't a member of the organization") }; if user_to_confirm.atype != UserOrgType::User && headers.org_user_type != UserOrgType::Owner { @@ -1287,9 +1262,8 @@ async fn get_user( _headers: AdminHeaders, mut conn: DbConn, ) -> JsonResult { - let user = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await { - Some(user) => user, - None => err!("The specified user isn't a member of the organization"), + let Some(user) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await else { + err!("The specified user isn't a member of the organization") }; // In this case, when groups are requested we also need to include collections. @@ -1331,14 +1305,12 @@ async fn edit_user( ) -> EmptyResult { let data: EditUserData = data.into_inner(); - let new_type = match UserOrgType::from_str(&data.r#type.into_string()) { - Some(new_type) => new_type, - None => err!("Invalid type"), + let Some(new_type) = UserOrgType::from_str(&data.r#type.into_string()) else { + err!("Invalid type") }; - let mut user_to_edit = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await { - Some(user) => user, - None => err!("The specified user isn't member of the organization"), + let Some(mut user_to_edit) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await else { + err!("The specified user isn't member of the organization") }; if new_type != user_to_edit.atype @@ -1490,9 +1462,8 @@ async fn _delete_user( conn: &mut DbConn, nt: &Notify<'_>, ) -> EmptyResult { - let user_to_delete = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { - Some(user) => user, - None => err!("User to delete isn't member of the organization"), + let Some(user_to_delete) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await else { + err!("User to delete isn't member of the organization") }; if user_to_delete.atype != UserOrgType::User && headers.org_user_type != UserOrgType::Owner { @@ -1725,9 +1696,8 @@ async fn list_policies_token(org_id: &str, token: &str, mut conn: DbConn) -> Jso let invite = decode_invite(token)?; - let invite_org_id = match invite.org_id { - Some(invite_org_id) => invite_org_id, - None => err!("Invalid token"), + let Some(invite_org_id) = invite.org_id else { + err!("Invalid token") }; if invite_org_id != org_id { @@ -1747,9 +1717,8 @@ async fn list_policies_token(org_id: &str, token: &str, mut conn: DbConn) -> Jso #[get("/organizations/<org_id>/policies/<pol_type>")] async fn get_policy(org_id: &str, pol_type: i32, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { - let pol_type_enum = match OrgPolicyType::from_i32(pol_type) { - Some(pt) => pt, - None => err!("Invalid or unsupported policy type"), + let Some(pol_type_enum) = OrgPolicyType::from_i32(pol_type) else { + err!("Invalid or unsupported policy type") }; let policy = match OrgPolicy::find_by_org_and_type(org_id, pol_type_enum, &mut conn).await { @@ -1778,9 +1747,8 @@ async fn put_policy( ) -> JsonResult { let data: PolicyData = data.into_inner(); - let pol_type_enum = match OrgPolicyType::from_i32(pol_type) { - Some(pt) => pt, - None => err!("Invalid or unsupported policy type"), + let Some(pol_type_enum) = OrgPolicyType::from_i32(pol_type) else { + err!("Invalid or unsupported policy type") }; // Bitwarden only allows the Reset Password policy when Single Org policy is enabled @@ -2437,9 +2405,8 @@ async fn put_group( err!("Group support is disabled"); } - let group = match Group::find_by_uuid(group_id, &mut conn).await { - Some(group) => group, - None => err!("Group not found"), + let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await else { + err!("Group not found", "Group uuid is invalid or does not belong to the organization") }; let group_request = data.into_inner(); @@ -2502,15 +2469,14 @@ async fn add_update_group( }))) } -#[get("/organizations/<_org_id>/groups/<group_id>/details")] -async fn get_group_details(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { +#[get("/organizations/<org_id>/groups/<group_id>/details")] +async fn get_group_details(org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { if !CONFIG.org_groups_enabled() { err!("Group support is disabled"); } - let group = match Group::find_by_uuid(group_id, &mut conn).await { - Some(group) => group, - _ => err!("Group could not be found!"), + let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await else { + err!("Group not found", "Group uuid is invalid or does not belong to the organization") }; Ok(Json(group.to_json_details(&mut conn).await)) @@ -2531,9 +2497,8 @@ async fn _delete_group(org_id: &str, group_id: &str, headers: &AdminHeaders, con err!("Group support is disabled"); } - let group = match Group::find_by_uuid(group_id, conn).await { - Some(group) => group, - _ => err!("Group not found"), + let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, conn).await else { + err!("Group not found", "Group uuid is invalid or does not belong to the organization") }; log_event( @@ -2569,29 +2534,27 @@ async fn bulk_delete_groups( Ok(()) } -#[get("/organizations/<_org_id>/groups/<group_id>")] -async fn get_group(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { +#[get("/organizations/<org_id>/groups/<group_id>")] +async fn get_group(org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { if !CONFIG.org_groups_enabled() { err!("Group support is disabled"); } - let group = match Group::find_by_uuid(group_id, &mut conn).await { - Some(group) => group, - _ => err!("Group not found"), + let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await else { + err!("Group not found", "Group uuid is invalid or does not belong to the organization") }; Ok(Json(group.to_json())) } -#[get("/organizations/<_org_id>/groups/<group_id>/users")] -async fn get_group_users(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { +#[get("/organizations/<org_id>/groups/<group_id>/users")] +async fn get_group_users(org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { if !CONFIG.org_groups_enabled() { err!("Group support is disabled"); } - match Group::find_by_uuid(group_id, &mut conn).await { - Some(_) => { /* Do nothing */ } - _ => err!("Group could not be found!"), + if Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await.is_none() { + err!("Group could not be found!", "Group uuid is invalid or does not belong to the organization") }; let group_users: Vec<String> = GroupUser::find_by_group(group_id, &mut conn) @@ -2615,9 +2578,8 @@ async fn put_group_users( err!("Group support is disabled"); } - match Group::find_by_uuid(group_id, &mut conn).await { - Some(_) => { /* Do nothing */ } - _ => err!("Group could not be found!"), + if Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await.is_none() { + err!("Group could not be found!", "Group uuid is invalid or does not belong to the organization") }; GroupUser::delete_all_by_group(group_id, &mut conn).await?; @@ -2642,15 +2604,14 @@ async fn put_group_users( Ok(()) } -#[get("/organizations/<_org_id>/users/<user_id>/groups")] -async fn get_user_groups(_org_id: &str, user_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { +#[get("/organizations/<org_id>/users/<user_id>/groups")] +async fn get_user_groups(org_id: &str, user_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { if !CONFIG.org_groups_enabled() { err!("Group support is disabled"); } - match UserOrganization::find_by_uuid(user_id, &mut conn).await { - Some(_) => { /* Do nothing */ } - _ => err!("User could not be found!"), + if UserOrganization::find_by_uuid_and_org(user_id, org_id, &mut conn).await.is_none() { + err!("User could not be found!") }; let user_groups: Vec<String> = @@ -2688,13 +2649,8 @@ async fn put_user_groups( err!("Group support is disabled"); } - let user_org = match UserOrganization::find_by_uuid(org_user_id, &mut conn).await { - Some(uo) => uo, - _ => err!("User could not be found!"), - }; - - if user_org.org_uuid != org_id { - err!("Group doesn't belong to organization"); + if UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await.is_none() { + err!("User could not be found or does not belong to the organization."); } GroupUser::delete_all_by_user(org_user_id, &mut conn).await?; @@ -2742,22 +2698,12 @@ async fn delete_group_user( err!("Group support is disabled"); } - let user_org = match UserOrganization::find_by_uuid(org_user_id, &mut conn).await { - Some(uo) => uo, - _ => err!("User could not be found!"), - }; - - if user_org.org_uuid != org_id { - err!("User doesn't belong to organization"); + if UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await.is_none() { + err!("User could not be found or does not belong to the organization."); } - let group = match Group::find_by_uuid(group_id, &mut conn).await { - Some(g) => g, - _ => err!("Group could not be found!"), - }; - - if group.organizations_uuid != org_id { - err!("Group doesn't belong to organization"); + if Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await.is_none() { + err!("Group could not be found or does not belong to the organization."); } log_event( @@ -2794,9 +2740,8 @@ struct OrganizationUserResetPasswordRequest { // Just add it here in case they will #[get("/organizations/<org_id>/public-key")] async fn get_organization_public_key(org_id: &str, _headers: Headers, mut conn: DbConn) -> JsonResult { - let org = match Organization::find_by_uuid(org_id, &mut conn).await { - Some(organization) => organization, - None => err!("Organization not found"), + let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else { + err!("Organization not found") }; Ok(Json(json!({ @@ -2821,19 +2766,16 @@ async fn put_reset_password( mut conn: DbConn, nt: Notify<'_>, ) -> EmptyResult { - let org = match Organization::find_by_uuid(org_id, &mut conn).await { - Some(org) => org, - None => err!("Required organization not found"), + let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else { + err!("Required organization not found") }; - let org_user = match UserOrganization::find_by_uuid_and_org(org_user_id, &org.uuid, &mut conn).await { - Some(user) => user, - None => err!("User to reset isn't member of required organization"), + let Some(org_user) = UserOrganization::find_by_uuid_and_org(org_user_id, &org.uuid, &mut conn).await else { + err!("User to reset isn't member of required organization") }; - let user = match User::find_by_uuid(&org_user.user_uuid, &mut conn).await { - Some(user) => user, - None => err!("User not found"), + let Some(user) = User::find_by_uuid(&org_user.user_uuid, &mut conn).await else { + err!("User not found") }; check_reset_password_applicable_and_permissions(org_id, org_user_id, &headers, &mut conn).await?; @@ -2880,19 +2822,16 @@ async fn get_reset_password_details( headers: AdminHeaders, mut conn: DbConn, ) -> JsonResult { - let org = match Organization::find_by_uuid(org_id, &mut conn).await { - Some(org) => org, - None => err!("Required organization not found"), + let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else { + err!("Required organization not found") }; - let org_user = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await { - Some(user) => user, - None => err!("User to reset isn't member of required organization"), + let Some(org_user) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await else { + err!("User to reset isn't member of required organization") }; - let user = match User::find_by_uuid(&org_user.user_uuid, &mut conn).await { - Some(user) => user, - None => err!("User not found"), + let Some(user) = User::find_by_uuid(&org_user.user_uuid, &mut conn).await else { + err!("User not found") }; check_reset_password_applicable_and_permissions(org_id, org_user_id, &headers, &mut conn).await?; @@ -2918,9 +2857,8 @@ async fn check_reset_password_applicable_and_permissions( ) -> EmptyResult { check_reset_password_applicable(org_id, conn).await?; - let target_user = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { - Some(user) => user, - None => err!("Reset target user not found"), + let Some(target_user) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await else { + err!("Reset target user not found") }; // Resetting user must be higher/equal to user to reset @@ -2936,9 +2874,8 @@ async fn check_reset_password_applicable(org_id: &str, conn: &mut DbConn) -> Emp err!("Password reset is not supported on an email-disabled instance."); } - let policy = match OrgPolicy::find_by_org_and_type(org_id, OrgPolicyType::ResetPassword, conn).await { - Some(p) => p, - None => err!("Policy not found"), + let Some(policy) = OrgPolicy::find_by_org_and_type(org_id, OrgPolicyType::ResetPassword, conn).await else { + err!("Policy not found") }; if !policy.enabled { @@ -2956,9 +2893,8 @@ async fn put_reset_password_enrollment( data: Json<OrganizationUserResetPasswordEnrollmentRequest>, mut conn: DbConn, ) -> EmptyResult { - let mut org_user = match UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await { - Some(u) => u, - None => err!("User to enroll isn't member of required organization"), + let Some(mut org_user) = UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await else { + err!("User to enroll isn't member of required organization") }; check_reset_password_applicable(org_id, &mut conn).await?; diff --git a/src/api/core/public.rs b/src/api/core/public.rs index 737d30dd..3b3e74cb 100644 --- a/src/api/core/public.rs +++ b/src/api/core/public.rs @@ -203,9 +203,8 @@ impl<'r> FromRequest<'r> for PublicToken { None => err_handler!("No access token provided"), }; // Check JWT token is valid and get device and user from it - let claims = match auth::decode_api_org(access_token) { - Ok(claims) => claims, - Err(_) => err_handler!("Invalid claim"), + let Ok(claims) = auth::decode_api_org(access_token) else { + err_handler!("Invalid claim") }; // Check if time is between claims.nbf and claims.exp let time_now = Utc::now().timestamp(); @@ -227,13 +226,11 @@ impl<'r> FromRequest<'r> for PublicToken { Outcome::Success(conn) => conn, _ => err_handler!("Error getting DB"), }; - let org_uuid = match claims.client_id.strip_prefix("organization.") { - Some(uuid) => uuid, - None => err_handler!("Malformed client_id"), + let Some(org_uuid) = claims.client_id.strip_prefix("organization.") else { + err_handler!("Malformed client_id") }; - let org_api_key = match OrganizationApiKey::find_by_org_uuid(org_uuid, &conn).await { - Some(org_api_key) => org_api_key, - None => err_handler!("Invalid client_id"), + let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(org_uuid, &conn).await else { + err_handler!("Invalid client_id") }; if org_api_key.org_uuid != claims.client_sub { err_handler!("Token not issued for this org"); diff --git a/src/api/core/sends.rs b/src/api/core/sends.rs index a7e5bcf0..b98ecf70 100644 --- a/src/api/core/sends.rs +++ b/src/api/core/sends.rs @@ -159,16 +159,10 @@ async fn get_sends(headers: Headers, mut conn: DbConn) -> Json<Value> { #[get("/sends/<uuid>")] async fn get_send(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult { - let send = match Send::find_by_uuid(uuid, &mut conn).await { - Some(send) => send, - None => err!("Send not found"), - }; - - if send.user_uuid.as_ref() != Some(&headers.user.uuid) { - err!("Send is not owned by user") + match Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await { + Some(send) => Ok(Json(send.to_json())), + None => err!("Send not found", "Invalid uuid or does not belong to user"), } - - Ok(Json(send.to_json())) } #[post("/sends", data = "<data>")] @@ -371,22 +365,14 @@ async fn post_send_file_v2_data( let mut data = data.into_inner(); - let Some(send) = Send::find_by_uuid(send_uuid, &mut conn).await else { - err!("Send not found. Unable to save the file.") + let Some(send) = Send::find_by_uuid_and_user(send_uuid, &headers.user.uuid, &mut conn).await else { + err!("Send not found. Unable to save the file.", "Invalid uuid or does not belong to user.") }; if send.atype != SendType::File as i32 { err!("Send is not a file type send."); } - let Some(send_user_id) = &send.user_uuid else { - err!("Sends are only supported for users at the moment.") - }; - - if send_user_id != &headers.user.uuid { - err!("Send doesn't belong to user."); - } - let Ok(send_data) = serde_json::from_str::<SendFileData>(&send.data) else { err!("Unable to decode send data as json.") }; @@ -456,9 +442,8 @@ async fn post_access( ip: ClientIp, nt: Notify<'_>, ) -> JsonResult { - let mut send = match Send::find_by_access_id(access_id, &mut conn).await { - Some(s) => s, - None => err_code!(SEND_INACCESSIBLE_MSG, 404), + let Some(mut send) = Send::find_by_access_id(access_id, &mut conn).await else { + err_code!(SEND_INACCESSIBLE_MSG, 404) }; if let Some(max_access_count) = send.max_access_count { @@ -517,9 +502,8 @@ async fn post_access_file( mut conn: DbConn, nt: Notify<'_>, ) -> JsonResult { - let mut send = match Send::find_by_uuid(send_id, &mut conn).await { - Some(s) => s, - None => err_code!(SEND_INACCESSIBLE_MSG, 404), + let Some(mut send) = Send::find_by_uuid(send_id, &mut conn).await else { + err_code!(SEND_INACCESSIBLE_MSG, 404) }; if let Some(max_access_count) = send.max_access_count { @@ -582,16 +566,15 @@ async fn download_send(send_id: SafeString, file_id: SafeString, t: &str) -> Opt None } -#[put("/sends/<id>", data = "<data>")] -async fn put_send(id: &str, data: Json<SendData>, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { +#[put("/sends/<uuid>", data = "<data>")] +async fn put_send(uuid: &str, data: Json<SendData>, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { enforce_disable_send_policy(&headers, &mut conn).await?; let data: SendData = data.into_inner(); enforce_disable_hide_email_policy(&data, &headers, &mut conn).await?; - let mut send = match Send::find_by_uuid(id, &mut conn).await { - Some(s) => s, - None => err!("Send not found"), + let Some(mut send) = Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else { + err!("Send not found", "Send uuid is invalid or does not belong to user") }; update_send_from_data(&mut send, data, &headers, &mut conn, &nt, UpdateType::SyncSendUpdate).await?; @@ -657,17 +640,12 @@ pub async fn update_send_from_data( Ok(()) } -#[delete("/sends/<id>")] -async fn delete_send(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { - let send = match Send::find_by_uuid(id, &mut conn).await { - Some(s) => s, - None => err!("Send not found"), +#[delete("/sends/<uuid>")] +async fn delete_send(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { + let Some(send) = Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else { + err!("Send not found", "Invalid send uuid, or does not belong to user") }; - if send.user_uuid.as_ref() != Some(&headers.user.uuid) { - err!("Send is not owned by user") - } - send.delete(&mut conn).await?; nt.send_send_update( UpdateType::SyncSendDelete, @@ -681,19 +659,14 @@ async fn delete_send(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_ Ok(()) } -#[put("/sends/<id>/remove-password")] -async fn put_remove_password(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { +#[put("/sends/<uuid>/remove-password")] +async fn put_remove_password(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { enforce_disable_send_policy(&headers, &mut conn).await?; - let mut send = match Send::find_by_uuid(id, &mut conn).await { - Some(s) => s, - None => err!("Send not found"), + let Some(mut send) = Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else { + err!("Send not found", "Invalid send uuid, or does not belong to user") }; - if send.user_uuid.as_ref() != Some(&headers.user.uuid) { - err!("Send is not owned by user") - } - send.set_password(None); send.save(&mut conn).await?; nt.send_send_update( diff --git a/src/api/core/two_factor/authenticator.rs b/src/api/core/two_factor/authenticator.rs index 9d4bd480..64cc6486 100644 --- a/src/api/core/two_factor/authenticator.rs +++ b/src/api/core/two_factor/authenticator.rs @@ -117,9 +117,8 @@ pub async fn validate_totp_code( ) -> EmptyResult { use totp_lite::{totp_custom, Sha1}; - let decoded_secret = match BASE32.decode(secret.as_bytes()) { - Ok(s) => s, - Err(_) => err!("Invalid TOTP secret"), + let Ok(decoded_secret) = BASE32.decode(secret.as_bytes()) else { + err!("Invalid TOTP secret") }; let mut twofactor = diff --git a/src/api/core/two_factor/duo.rs b/src/api/core/two_factor/duo.rs index 6de2935d..76421043 100644 --- a/src/api/core/two_factor/duo.rs +++ b/src/api/core/two_factor/duo.rs @@ -232,9 +232,8 @@ async fn get_user_duo_data(uuid: &str, conn: &mut DbConn) -> DuoStatus { let type_ = TwoFactorType::Duo as i32; // If the user doesn't have an entry, disabled - let twofactor = match TwoFactor::find_by_user_and_type(uuid, type_, conn).await { - Some(t) => t, - None => return DuoStatus::Disabled(DuoData::global().is_some()), + let Some(twofactor) = TwoFactor::find_by_user_and_type(uuid, type_, conn).await else { + return DuoStatus::Disabled(DuoData::global().is_some()); }; // If the user has the required values, we use those @@ -333,14 +332,12 @@ fn parse_duo_values(key: &str, val: &str, ikey: &str, prefix: &str, time: i64) - err!("Prefixes don't match") } - let cookie_vec = match BASE64.decode(u_b64.as_bytes()) { - Ok(c) => c, - Err(_) => err!("Invalid Duo cookie encoding"), + let Ok(cookie_vec) = BASE64.decode(u_b64.as_bytes()) else { + err!("Invalid Duo cookie encoding") }; - let cookie = match String::from_utf8(cookie_vec) { - Ok(c) => c, - Err(_) => err!("Invalid Duo cookie encoding"), + let Ok(cookie) = String::from_utf8(cookie_vec) else { + err!("Invalid Duo cookie encoding") }; let cookie_split: Vec<&str> = cookie.split('|').collect(); diff --git a/src/api/core/two_factor/email.rs b/src/api/core/two_factor/email.rs index 293c0671..09f2f3b7 100644 --- a/src/api/core/two_factor/email.rs +++ b/src/api/core/two_factor/email.rs @@ -40,9 +40,8 @@ async fn send_email_login(data: Json<SendEmailLoginData>, mut conn: DbConn) -> E use crate::db::models::User; // Get the user - let user = match User::find_by_mail(&data.email, &mut conn).await { - Some(user) => user, - None => err!("Username or password is incorrect. Try again."), + let Some(user) = User::find_by_mail(&data.email, &mut conn).await else { + err!("Username or password is incorrect. Try again.") }; // Check password @@ -174,9 +173,8 @@ async fn email(data: Json<EmailData>, headers: Headers, mut conn: DbConn) -> Jso let mut email_data = EmailTokenData::from_json(&twofactor.data)?; - let issued_token = match &email_data.last_token { - Some(t) => t, - _ => err!("No token available"), + let Some(issued_token) = &email_data.last_token else { + err!("No token available") }; if !crypto::ct_eq(issued_token, data.token) { @@ -205,14 +203,13 @@ pub async fn validate_email_code_str(user_uuid: &str, token: &str, data: &str, c let mut twofactor = TwoFactor::find_by_user_and_type(user_uuid, TwoFactorType::Email as i32, conn) .await .map_res("Two factor not found")?; - let issued_token = match &email_data.last_token { - Some(t) => t, - _ => err!( + let Some(issued_token) = &email_data.last_token else { + err!( "No token available", ErrorEvent { event: EventType::UserFailedLogIn2fa } - ), + ) }; if !crypto::ct_eq(issued_token, token) { diff --git a/src/api/core/two_factor/mod.rs b/src/api/core/two_factor/mod.rs index e3795eb8..486b526a 100644 --- a/src/api/core/two_factor/mod.rs +++ b/src/api/core/two_factor/mod.rs @@ -85,9 +85,8 @@ async fn recover(data: Json<RecoverTwoFactor>, client_headers: ClientHeaders, mu use crate::db::models::User; // Get the user - let mut user = match User::find_by_mail(&data.email, &mut conn).await { - Some(user) => user, - None => err!("Username or password is incorrect. Try again."), + let Some(mut user) = User::find_by_mail(&data.email, &mut conn).await else { + err!("Username or password is incorrect. Try again.") }; // Check password diff --git a/src/api/core/two_factor/webauthn.rs b/src/api/core/two_factor/webauthn.rs index 52ca70c4..9ee83d38 100644 --- a/src/api/core/two_factor/webauthn.rs +++ b/src/api/core/two_factor/webauthn.rs @@ -309,17 +309,16 @@ async fn delete_webauthn(data: Json<DeleteU2FData>, headers: Headers, mut conn: err!("Invalid password"); } - let mut tf = - match TwoFactor::find_by_user_and_type(&headers.user.uuid, TwoFactorType::Webauthn as i32, &mut conn).await { - Some(tf) => tf, - None => err!("Webauthn data not found!"), - }; + let Some(mut tf) = + TwoFactor::find_by_user_and_type(&headers.user.uuid, TwoFactorType::Webauthn as i32, &mut conn).await + else { + err!("Webauthn data not found!") + }; let mut data: Vec<WebauthnRegistration> = serde_json::from_str(&tf.data)?; - let item_pos = match data.iter().position(|r| r.id == id) { - Some(p) => p, - None => err!("Webauthn entry not found"), + let Some(item_pos) = data.iter().position(|r| r.id == id) else { + err!("Webauthn entry not found") }; let removed_item = data.remove(item_pos); |