From 9cd400db6c5da858a4f49eb883469cbd6cb7337d Mon Sep 17 00:00:00 2001 From: Mathijs van Veluw Date: Sat, 14 Dec 2024 00:55:34 +0100 Subject: [PATCH] Some refactoring and optimizations (#5291) - Refactored several code to use more modern syntax - Made some checks a bit more strict - Updated crates Signed-off-by: BlackDex --- Cargo.lock | 36 +-- src/api/admin.rs | 15 +- src/api/core/accounts.rs | 96 +++----- src/api/core/ciphers.rs | 104 +++----- src/api/core/emergency_access.rs | 170 ++++++------- src/api/core/folders.rs | 30 +-- src/api/core/organizations.rs | 296 +++++++++-------------- src/api/core/public.rs | 15 +- src/api/core/sends.rs | 69 ++---- src/api/core/two_factor/authenticator.rs | 5 +- src/api/core/two_factor/duo.rs | 15 +- src/api/core/two_factor/email.rs | 17 +- src/api/core/two_factor/mod.rs | 5 +- src/api/core/two_factor/webauthn.rs | 15 +- src/api/identity.rs | 38 ++- src/api/push.rs | 9 +- src/auth.rs | 20 +- src/db/models/auth_request.rs | 11 + src/db/models/folder.rs | 3 +- src/db/models/group.rs | 3 +- src/db/models/org_policy.rs | 10 - src/db/models/send.rs | 16 +- src/mail.rs | 10 +- 23 files changed, 414 insertions(+), 594 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2107b75c..2f920b18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -489,9 +489,9 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" [[package]] name = "cc" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ "shlex", ] @@ -1524,7 +1524,7 @@ dependencies = [ "http 1.2.0", "hyper 1.5.1", "hyper-util", - "rustls 0.23.19", + "rustls 0.23.20", "rustls-pki-types", "tokio", "tokio-rustls 0.26.1", @@ -2618,9 +2618,9 @@ dependencies = [ [[package]] name = "quanta" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" +checksum = "773ce68d0bb9bc7ef20be3536ffe94e223e1f365bd374108b2659fac0c65cfe6" dependencies = [ "crossbeam-utils", "libc", @@ -2704,9 +2704,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags", ] @@ -3031,9 +3031,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.19" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "once_cell", "rustls-pki-types", @@ -3062,9 +3062,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" [[package]] name = "rustls-webpki" @@ -3173,15 +3173,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] @@ -3198,9 +3198,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -3652,7 +3652,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.23.19", + "rustls 0.23.20", "tokio", ] diff --git a/src/api/admin.rs b/src/api/admin.rs index 45eb5972..f49f6ed3 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -495,11 +495,11 @@ struct UserOrgTypeData { async fn update_user_org_type(data: Json, token: AdminToken, mut conn: DbConn) -> EmptyResult { let data: UserOrgTypeData = data.into_inner(); - let mut user_to_edit = - match UserOrganization::find_by_user_and_org(&data.user_uuid, &data.org_uuid, &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_user_and_org(&data.user_uuid, &data.org_uuid, &mut conn).await + else { + err!("The specified user isn't member of the organization") + }; let new_type = match UserOrgType::from_str(&data.user_type.into_string()) { Some(new_type) => new_type as i32, @@ -602,9 +602,8 @@ async fn get_json_api(url: &str) -> Result { } async fn has_http_access() -> bool { - let req = match make_http_request(Method::HEAD, "https://github.com/dani-garcia/vaultwarden") { - Ok(r) => r, - Err(_) => return false, + let Ok(req) = make_http_request(Method::HEAD, "https://github.com/dani-garcia/vaultwarden") else { + return false; }; match req.send().await { Ok(r) => r.status().is_success(), 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, 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, 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, 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, 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, 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, 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, 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 { 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, 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/")] 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 { #[get("/ciphers/")] 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::::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::::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//attachment/")] 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, 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, 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//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 { #[get("/folders/")] 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/")] 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//collections/")] @@ -601,12 +577,11 @@ struct DeleteCollectionData { org_id: String, } -#[post("/organizations//collections//delete", data = "<_data>")] +#[post("/organizations//collections//delete")] async fn post_organization_collection_delete( org_id: &str, col_id: &str, headers: ManagerHeaders, - _data: Json, 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 = if CONFIG.org_groups_enabled() { @@ -695,9 +670,8 @@ async fn get_org_collection_detail( #[get("/organizations//collections//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, } -#[post("/organizations//users/<_org_user_id>/accept", data = "")] -async fn accept_invite(org_id: &str, _org_user_id: &str, data: Json, mut conn: DbConn) -> EmptyResult { +#[post("/organizations//users//accept", data = "")] +async fn accept_invite(org_id: &str, org_user_id: &str, data: Json, 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//policies/")] 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//details")] -async fn get_group_details(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { +#[get("/organizations//groups//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/")] -async fn get_group(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { +#[get("/organizations//groups/")] +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//users")] -async fn get_group_users(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { +#[get("/organizations//groups//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 = 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//groups")] -async fn get_user_groups(_org_id: &str, user_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { +#[get("/organizations//users//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 = @@ -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//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, 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 { #[get("/sends/")] 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 = "")] @@ -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::(&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/", data = "")] -async fn put_send(id: &str, data: Json, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { +#[put("/sends/", data = "")] +async fn put_send(uuid: &str, data: Json, 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/")] -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/")] +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//remove-password")] -async fn put_remove_password(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { +#[put("/sends//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, 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, 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, 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, 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 = 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); diff --git a/src/api/identity.rs b/src/api/identity.rs index 445d61fd..13248f0a 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -157,9 +157,8 @@ async fn _password_login( // Get the user let username = data.username.as_ref().unwrap().trim(); - let mut user = match User::find_by_mail(username, conn).await { - Some(user) => user, - None => err!("Username or password is incorrect. Try again", format!("IP: {}. Username: {}.", ip.ip, username)), + let Some(mut user) = User::find_by_mail(username, conn).await else { + err!("Username or password is incorrect. Try again", format!("IP: {}. Username: {}.", ip.ip, username)) }; // Set the user_uuid here to be passed back used for event logging. @@ -180,7 +179,8 @@ async fn _password_login( // If we get an auth request, we don't check the user's password, but the access code of the auth request if let Some(ref auth_request_uuid) = data.auth_request { - let Some(auth_request) = AuthRequest::find_by_uuid(auth_request_uuid.as_str(), conn).await else { + let Some(auth_request) = AuthRequest::find_by_uuid_and_user(auth_request_uuid.as_str(), &user.uuid, conn).await + else { err!( "Auth request not found. Try again.", format!("IP: {}. Username: {}.", ip.ip, username), @@ -382,13 +382,11 @@ async fn _user_api_key_login( ) -> JsonResult { // Get the user via the client_id let client_id = data.client_id.as_ref().unwrap(); - let client_user_uuid = match client_id.strip_prefix("user.") { - Some(uuid) => uuid, - None => err!("Malformed client_id", format!("IP: {}.", ip.ip)), + let Some(client_user_uuid) = client_id.strip_prefix("user.") else { + err!("Malformed client_id", format!("IP: {}.", ip.ip)) }; - let user = match User::find_by_uuid(client_user_uuid, conn).await { - Some(user) => user, - None => err!("Invalid client_id", format!("IP: {}.", ip.ip)), + let Some(user) = User::find_by_uuid(client_user_uuid, conn).await else { + err!("Invalid client_id", format!("IP: {}.", ip.ip)) }; // Set the user_uuid here to be passed back used for event logging. @@ -471,13 +469,11 @@ async fn _user_api_key_login( async fn _organization_api_key_login(data: ConnectData, conn: &mut DbConn, ip: &ClientIp) -> JsonResult { // Get the org via the client_id let client_id = data.client_id.as_ref().unwrap(); - let org_uuid = match client_id.strip_prefix("organization.") { - Some(uuid) => uuid, - None => err!("Malformed client_id", format!("IP: {}.", ip.ip)), + let Some(org_uuid) = client_id.strip_prefix("organization.") else { + err!("Malformed client_id", format!("IP: {}.", ip.ip)) }; - let org_api_key = match OrganizationApiKey::find_by_org_uuid(org_uuid, conn).await { - Some(org_api_key) => org_api_key, - None => err!("Invalid client_id", format!("IP: {}.", ip.ip)), + let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(org_uuid, conn).await else { + err!("Invalid client_id", format!("IP: {}.", ip.ip)) }; // Check API key. @@ -676,9 +672,8 @@ async fn _json_err_twofactor( } Some(tf_type @ TwoFactorType::YubiKey) => { - let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await { - Some(tf) => tf, - None => err!("No YubiKey devices registered"), + let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await else { + err!("No YubiKey devices registered") }; let yubikey_metadata: yubikey::YubikeyMetadata = serde_json::from_str(&twofactor.data)?; @@ -689,9 +684,8 @@ async fn _json_err_twofactor( } Some(tf_type @ TwoFactorType::Email) => { - let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await { - Some(tf) => tf, - None => err!("No twofactor email registered"), + let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await else { + err!("No twofactor email registered") }; // Send email immediately if email is the only 2FA option diff --git a/src/api/push.rs b/src/api/push.rs index d6abfc49..7396a68d 100644 --- a/src/api/push.rs +++ b/src/api/push.rs @@ -155,12 +155,9 @@ pub async fn push_cipher_update( if cipher.organization_uuid.is_some() { return; }; - let user_uuid = match &cipher.user_uuid { - Some(c) => c, - None => { - debug!("Cipher has no uuid"); - return; - } + let Some(user_uuid) = &cipher.user_uuid else { + debug!("Cipher has no uuid"); + return; }; if Device::check_user_has_push_device(user_uuid, conn).await { diff --git a/src/auth.rs b/src/auth.rs index 809ef9fd..15910679 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -471,9 +471,8 @@ impl<'r> FromRequest<'r> for Headers { }; // Check JWT token is valid and get device and user from it - let claims = match decode_login(access_token) { - Ok(claims) => claims, - Err(_) => err_handler!("Invalid claim"), + let Ok(claims) = decode_login(access_token) else { + err_handler!("Invalid claim") }; let device_uuid = claims.device; @@ -484,23 +483,20 @@ impl<'r> FromRequest<'r> for Headers { _ => err_handler!("Error getting DB"), }; - let device = match Device::find_by_uuid_and_user(&device_uuid, &user_uuid, &mut conn).await { - Some(device) => device, - None => err_handler!("Invalid device id"), + let Some(device) = Device::find_by_uuid_and_user(&device_uuid, &user_uuid, &mut conn).await else { + err_handler!("Invalid device id") }; - let user = match User::find_by_uuid(&user_uuid, &mut conn).await { - Some(user) => user, - None => err_handler!("Device has no user associated"), + let Some(user) = User::find_by_uuid(&user_uuid, &mut conn).await else { + err_handler!("Device has no user associated") }; if user.security_stamp != claims.sstamp { if let Some(stamp_exception) = user.stamp_exception.as_deref().and_then(|s| serde_json::from_str::(s).ok()) { - let current_route = match request.route().and_then(|r| r.name.as_deref()) { - Some(name) => name, - _ => err_handler!("Error getting current route for stamp exception"), + let Some(current_route) = request.route().and_then(|r| r.name.as_deref()) else { + err_handler!("Error getting current route for stamp exception") }; // Check if the stamp exception has expired first. diff --git a/src/db/models/auth_request.rs b/src/db/models/auth_request.rs index 9388c71a..3aca20cb 100644 --- a/src/db/models/auth_request.rs +++ b/src/db/models/auth_request.rs @@ -111,6 +111,17 @@ impl AuthRequest { }} } + pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option { + db_run! {conn: { + auth_requests::table + .filter(auth_requests::uuid.eq(uuid)) + .filter(auth_requests::user_uuid.eq(user_uuid)) + .first::(conn) + .ok() + .from_db() + }} + } + pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec { db_run! {conn: { auth_requests::table diff --git a/src/db/models/folder.rs b/src/db/models/folder.rs index 5370c9dd..45460720 100644 --- a/src/db/models/folder.rs +++ b/src/db/models/folder.rs @@ -120,10 +120,11 @@ impl Folder { Ok(()) } - pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option { + pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option { db_run! { conn: { folders::table .filter(folders::uuid.eq(uuid)) + .filter(folders::user_uuid.eq(user_uuid)) .first::(conn) .ok() .from_db() diff --git a/src/db/models/group.rs b/src/db/models/group.rs index e226512d..d9a08970 100644 --- a/src/db/models/group.rs +++ b/src/db/models/group.rs @@ -191,10 +191,11 @@ impl Group { }} } - pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option { + pub async fn find_by_uuid_and_org(uuid: &str, org_uuid: &str, conn: &mut DbConn) -> Option { db_run! { conn: { groups::table .filter(groups::uuid.eq(uuid)) + .filter(groups::organizations_uuid.eq(org_uuid)) .first::(conn) .ok() .from_db() diff --git a/src/db/models/org_policy.rs b/src/db/models/org_policy.rs index 23e583b4..14447c05 100644 --- a/src/db/models/org_policy.rs +++ b/src/db/models/org_policy.rs @@ -142,16 +142,6 @@ impl OrgPolicy { }} } - pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option { - db_run! { conn: { - org_policies::table - .filter(org_policies::uuid.eq(uuid)) - .first::(conn) - .ok() - .from_db() - }} - } - pub async fn find_by_org(org_uuid: &str, conn: &mut DbConn) -> Vec { db_run! { conn: { org_policies::table diff --git a/src/db/models/send.rs b/src/db/models/send.rs index 36944281..fb95f86b 100644 --- a/src/db/models/send.rs +++ b/src/db/models/send.rs @@ -268,9 +268,8 @@ impl Send { use data_encoding::BASE64URL_NOPAD; use uuid::Uuid; - let uuid_vec = match BASE64URL_NOPAD.decode(access_id.as_bytes()) { - Ok(v) => v, - Err(_) => return None, + let Ok(uuid_vec) = BASE64URL_NOPAD.decode(access_id.as_bytes()) else { + return None; }; let uuid = match Uuid::from_slice(&uuid_vec) { @@ -291,6 +290,17 @@ impl Send { }} } + pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option { + db_run! {conn: { + sends::table + .filter(sends::uuid.eq(uuid)) + .filter(sends::user_uuid.eq(user_uuid)) + .first::(conn) + .ok() + .from_db() + }} + } + pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec { db_run! {conn: { sends::table diff --git a/src/mail.rs b/src/mail.rs index 5ce4a079..1a32ae25 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -286,9 +286,8 @@ pub async fn send_invite( } } - let query_string = match query.query() { - None => err!("Failed to build invite URL query parameters"), - Some(query) => query, + let Some(query_string) = query.query() else { + err!("Failed to build invite URL query parameters") }; let (subject, body_html, body_text) = get_text( @@ -330,9 +329,8 @@ pub async fn send_emergency_access_invite( .append_pair("token", &encode_jwt(&claims)); } - let query_string = match query.query() { - None => err!("Failed to build emergency invite URL query parameters"), - Some(query) => query, + let Some(query_string) = query.query() else { + err!("Failed to build emergency invite URL query parameters") }; let (subject, body_html, body_text) = get_text(