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 <black.dex@gmail.com>
pull/5293/head
Mathijs van Veluw 2 weeks ago committed by GitHub
parent fd51230044
commit 9cd400db6c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

36
Cargo.lock generated

@ -489,9 +489,9 @@ checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.3" version = "1.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]
@ -1524,7 +1524,7 @@ dependencies = [
"http 1.2.0", "http 1.2.0",
"hyper 1.5.1", "hyper 1.5.1",
"hyper-util", "hyper-util",
"rustls 0.23.19", "rustls 0.23.20",
"rustls-pki-types", "rustls-pki-types",
"tokio", "tokio",
"tokio-rustls 0.26.1", "tokio-rustls 0.26.1",
@ -2618,9 +2618,9 @@ dependencies = [
[[package]] [[package]]
name = "quanta" name = "quanta"
version = "0.12.3" version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" checksum = "773ce68d0bb9bc7ef20be3536ffe94e223e1f365bd374108b2659fac0c65cfe6"
dependencies = [ dependencies = [
"crossbeam-utils", "crossbeam-utils",
"libc", "libc",
@ -2704,9 +2704,9 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.7" version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [ dependencies = [
"bitflags", "bitflags",
] ]
@ -3031,9 +3031,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.23.19" version = "0.23.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"rustls-pki-types", "rustls-pki-types",
@ -3062,9 +3062,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls-pki-types" name = "rustls-pki-types"
version = "1.10.0" version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37"
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
@ -3173,15 +3173,15 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.23" version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.215" version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -3198,9 +3198,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.215" version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3652,7 +3652,7 @@ version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
dependencies = [ dependencies = [
"rustls 0.23.19", "rustls 0.23.20",
"tokio", "tokio",
] ]

@ -495,11 +495,11 @@ struct UserOrgTypeData {
async fn update_user_org_type(data: Json<UserOrgTypeData>, token: AdminToken, mut conn: DbConn) -> EmptyResult { async fn update_user_org_type(data: Json<UserOrgTypeData>, token: AdminToken, mut conn: DbConn) -> EmptyResult {
let data: UserOrgTypeData = data.into_inner(); let data: UserOrgTypeData = data.into_inner();
let mut user_to_edit = let Some(mut user_to_edit) =
match UserOrganization::find_by_user_and_org(&data.user_uuid, &data.org_uuid, &mut conn).await { UserOrganization::find_by_user_and_org(&data.user_uuid, &data.org_uuid, &mut conn).await
Some(user) => user, else {
None => err!("The specified user isn't member of the organization"), err!("The specified user isn't member of the organization")
}; };
let new_type = match UserOrgType::from_str(&data.user_type.into_string()) { let new_type = match UserOrgType::from_str(&data.user_type.into_string()) {
Some(new_type) => new_type as i32, Some(new_type) => new_type as i32,
@ -602,9 +602,8 @@ async fn get_json_api<T: DeserializeOwned>(url: &str) -> Result<T, Error> {
} }
async fn has_http_access() -> bool { async fn has_http_access() -> bool {
let req = match make_http_request(Method::HEAD, "https://github.com/dani-garcia/vaultwarden") { let Ok(req) = make_http_request(Method::HEAD, "https://github.com/dani-garcia/vaultwarden") else {
Ok(r) => r, return false;
Err(_) => return false,
}; };
match req.send().await { match req.send().await {
Ok(r) => r.status().is_success(), Ok(r) => r.status().is_success(),

@ -574,9 +574,8 @@ async fn post_rotatekey(data: Json<KeyData>, headers: Headers, mut conn: DbConn,
// Skip `null` folder id entries. // Skip `null` folder id entries.
// See: https://github.com/bitwarden/clients/issues/8453 // See: https://github.com/bitwarden/clients/issues/8453
if let Some(folder_id) = folder_data.id { if let Some(folder_id) = folder_data.id {
let saved_folder = match existing_folders.iter_mut().find(|f| f.uuid == folder_id) { let Some(saved_folder) = existing_folders.iter_mut().find(|f| f.uuid == folder_id) else {
Some(folder) => folder, err!("Folder doesn't exist")
None => err!("Folder doesn't exist"),
}; };
saved_folder.name = folder_data.name; 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 // Update emergency access data
for emergency_access_data in data.emergency_access_keys { for emergency_access_data in data.emergency_access_keys {
let saved_emergency_access = let Some(saved_emergency_access) =
match existing_emergency_access.iter_mut().find(|ea| ea.uuid == emergency_access_data.id) { existing_emergency_access.iter_mut().find(|ea| ea.uuid == emergency_access_data.id)
Some(emergency_access) => emergency_access, else {
None => err!("Emergency access doesn't exist or is not owned by the user"), 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.key_encrypted = Some(emergency_access_data.key_encrypted);
saved_emergency_access.save(&mut conn).await? 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 // Update reset password data
for reset_password_data in data.reset_password_keys { 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) let Some(user_org) =
{ existing_user_orgs.iter_mut().find(|uo| uo.org_uuid == reset_password_data.organization_id)
Some(reset_password) => reset_password, else {
None => err!("Reset password doesn't exist"), err!("Reset password doesn't exist")
}; };
user_org.reset_password_key = Some(reset_password_data.reset_password_key); 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 // Update send data
for send_data in data.sends { for send_data in data.sends {
let send = match existing_sends.iter_mut().find(|s| &s.uuid == send_data.id.as_ref().unwrap()) { let Some(send) = existing_sends.iter_mut().find(|s| &s.uuid == send_data.id.as_ref().unwrap()) else {
Some(send) => send, err!("Send doesn't exist")
None => err!("Send doesn't exist"),
}; };
update_send_from_data(send, send_data, &headers, &mut conn, &nt, UpdateType::None).await?; 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 { for cipher_data in data.ciphers {
if cipher_data.organization_id.is_none() { 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()) { let Some(saved_cipher) = existing_ciphers.iter_mut().find(|c| &c.uuid == cipher_data.id.as_ref().unwrap())
Some(cipher) => cipher, else {
None => err!("Cipher doesn't exist"), err!("Cipher doesn't exist")
}; };
// Prevent triggering cipher updates via WebSockets by settings UpdateType::None // 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 { async fn post_verify_email_token(data: Json<VerifyEmailTokenData>, mut conn: DbConn) -> EmptyResult {
let data: VerifyEmailTokenData = data.into_inner(); let data: VerifyEmailTokenData = data.into_inner();
let mut user = match User::find_by_uuid(&data.user_id, &mut conn).await { let Some(mut user) = User::find_by_uuid(&data.user_id, &mut conn).await else {
Some(user) => user, err!("User doesn't exist")
None => err!("User doesn't exist"),
}; };
let claims = match decode_verify_email(&data.token) { let Ok(claims) = decode_verify_email(&data.token) else {
Ok(claims) => claims, err!("Invalid claim")
Err(_) => err!("Invalid claim"),
}; };
if claims.sub != user.uuid { if claims.sub != user.uuid {
err!("Invalid claim"); err!("Invalid claim");
@ -861,15 +857,14 @@ struct DeleteRecoverTokenData {
async fn post_delete_recover_token(data: Json<DeleteRecoverTokenData>, mut conn: DbConn) -> EmptyResult { async fn post_delete_recover_token(data: Json<DeleteRecoverTokenData>, mut conn: DbConn) -> EmptyResult {
let data: DeleteRecoverTokenData = data.into_inner(); let data: DeleteRecoverTokenData = data.into_inner();
let user = match User::find_by_uuid(&data.user_id, &mut conn).await { let Ok(claims) = decode_delete(&data.token) else {
Some(user) => user, err!("Invalid claim")
None => err!("User doesn't exist"),
}; };
let claims = match decode_delete(&data.token) { let Some(user) = User::find_by_uuid(&data.user_id, &mut conn).await else {
Ok(claims) => claims, err!("User doesn't exist")
Err(_) => err!("Invalid claim"),
}; };
if claims.sub != user.uuid { if claims.sub != user.uuid {
err!("Invalid claim"); err!("Invalid claim");
} }
@ -1041,11 +1036,8 @@ impl<'r> FromRequest<'r> for KnownDevice {
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> { 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 = 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()) { let Ok(email_bytes) = data_encoding::BASE64URL_NOPAD.decode(email_b64.as_bytes()) else {
Ok(bytes) => bytes, return Outcome::Error((Status::BadRequest, "X-Request-Email value failed to decode as base64url"));
Err(_) => {
return Outcome::Error((Status::BadRequest, "X-Request-Email value failed to decode as base64url"));
}
}; };
match String::from_utf8(email_bytes) { match String::from_utf8(email_bytes) {
Ok(email) => email, 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 data = data.into_inner();
let token = data.push_token; let token = data.push_token;
let mut device = match Device::find_by_uuid_and_user(&headers.device.uuid, &headers.user.uuid, &mut conn).await { let Some(mut device) = Device::find_by_uuid_and_user(&headers.device.uuid, &headers.user.uuid, &mut conn).await
Some(device) => device, else {
None => err!(format!("Error: device {uuid} should be present before a token can be assigned")), err!(format!("Error: device {uuid} should be present before a token can be assigned"))
}; };
// if the device already has been registered // if the device already has been registered
@ -1159,9 +1151,8 @@ async fn post_auth_request(
) -> JsonResult { ) -> JsonResult {
let data = data.into_inner(); let data = data.into_inner();
let user = match User::find_by_mail(&data.email, &mut conn).await { let Some(user) = User::find_by_mail(&data.email, &mut conn).await else {
Some(user) => user, err!("AuthRequest doesn't exist", "User not found")
None => err!("AuthRequest doesn't exist", "User not found"),
}; };
// Validate device uuid and type // Validate device uuid and type
@ -1199,15 +1190,10 @@ async fn post_auth_request(
#[get("/auth-requests/<uuid>")] #[get("/auth-requests/<uuid>")]
async fn get_auth_request(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult { 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 { let Some(auth_request) = AuthRequest::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
Some(auth_request) => auth_request, err!("AuthRequest doesn't exist", "Record not found or user uuid does not match")
None => err!("AuthRequest doesn't exist", "Record not found"),
}; };
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)); let response_date_utc = auth_request.response_date.map(|response_date| format_date(&response_date));
Ok(Json(json!({ Ok(Json(json!({
@ -1244,15 +1230,10 @@ async fn put_auth_request(
nt: Notify<'_>, nt: Notify<'_>,
) -> JsonResult { ) -> JsonResult {
let data = data.into_inner(); let data = data.into_inner();
let mut auth_request: AuthRequest = match AuthRequest::find_by_uuid(uuid, &mut conn).await { let Some(mut auth_request) = AuthRequest::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
Some(auth_request) => auth_request, err!("AuthRequest doesn't exist", "Record not found or user uuid does not match")
None => err!("AuthRequest doesn't exist", "Record not found"),
}; };
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() { if auth_request.approved.is_some() {
err!("An authentication request with the same device already exists") err!("An authentication request with the same device already exists")
} }
@ -1297,9 +1278,8 @@ async fn get_auth_request_response(
client_headers: ClientHeaders, client_headers: ClientHeaders,
mut conn: DbConn, mut conn: DbConn,
) -> JsonResult { ) -> JsonResult {
let auth_request = match AuthRequest::find_by_uuid(uuid, &mut conn).await { let Some(auth_request) = AuthRequest::find_by_uuid(uuid, &mut conn).await else {
Some(auth_request) => auth_request, err!("AuthRequest doesn't exist", "User not found")
None => err!("AuthRequest doesn't exist", "User not found"),
}; };
if auth_request.device_type != client_headers.device_type if auth_request.device_type != client_headers.device_type

@ -193,9 +193,8 @@ async fn get_ciphers(headers: Headers, mut conn: DbConn) -> Json<Value> {
#[get("/ciphers/<uuid>")] #[get("/ciphers/<uuid>")]
async fn get_cipher(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult { async fn get_cipher(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await { 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()); cipher.user_uuid = Some(headers.user.uuid.clone());
} }
if let Some(ref folder_id) = data.folder_id { if let Some(ref folder_uuid) = data.folder_id {
match Folder::find_by_uuid(folder_id, conn).await { if Folder::find_by_uuid_and_user(folder_uuid, &headers.user.uuid, conn).await.is_none() {
Some(folder) => { err!("Invalid folder", "Folder does not exist or belongs to another user");
if folder.user_uuid != headers.user.uuid {
err!("Folder is not owned by user")
}
}
None => err!("Folder doesn't exist"),
} }
} }
@ -661,9 +655,8 @@ async fn put_cipher(
) -> JsonResult { ) -> JsonResult {
let data: CipherData = data.into_inner(); let data: CipherData = data.into_inner();
let mut cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { let Some(mut cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
// TODO: Check if only the folder ID or favorite status is being changed. // TODO: Check if only the folder ID or favorite status is being changed.
@ -695,19 +688,13 @@ async fn put_cipher_partial(
) -> JsonResult { ) -> JsonResult {
let data: PartialCipherData = data.into_inner(); let data: PartialCipherData = data.into_inner();
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if let Some(ref folder_id) = data.folder_id { if let Some(ref folder_uuid) = data.folder_id {
match Folder::find_by_uuid(folder_id, &mut conn).await { if Folder::find_by_uuid_and_user(folder_uuid, &headers.user.uuid, &mut conn).await.is_none() {
Some(folder) => { err!("Invalid folder", "Folder does not exist or belongs to another user");
if folder.user_uuid != headers.user.uuid {
err!("Folder is not owned by user")
}
}
None => err!("Folder doesn't exist"),
} }
} }
@ -774,9 +761,8 @@ async fn post_collections_update(
) -> JsonResult { ) -> JsonResult {
let data: CollectionsAdminData = data.into_inner(); let data: CollectionsAdminData = data.into_inner();
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { 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); HashSet::<String>::from_iter(cipher.get_collections(headers.user.uuid.clone(), &mut conn).await);
for collection in posted_collections.symmetric_difference(&current_collections) { for collection in posted_collections.symmetric_difference(&current_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"), None => err!("Invalid collection ID provided"),
Some(collection) => { Some(collection) => {
if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await { if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await {
@ -851,9 +838,8 @@ async fn post_collections_admin(
) -> EmptyResult { ) -> EmptyResult {
let data: CollectionsAdminData = data.into_inner(); let data: CollectionsAdminData = data.into_inner();
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { 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); HashSet::<String>::from_iter(cipher.get_admin_collections(headers.user.uuid.clone(), &mut conn).await);
for collection in posted_collections.symmetric_difference(&current_collections) { for collection in posted_collections.symmetric_difference(&current_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"), None => err!("Invalid collection ID provided"),
Some(collection) => { Some(collection) => {
if collection.is_writable_by_user(&headers.user.uuid, &mut conn).await { 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. /// redirects to the same location as before the v2 API.
#[get("/ciphers/<uuid>/attachment/<attachment_id>")] #[get("/ciphers/<uuid>/attachment/<attachment_id>")]
async fn get_attachment(uuid: &str, attachment_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult { 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 { let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await { if !cipher.is_accessible_to_user(&headers.user.uuid, &mut conn).await {
@ -1084,9 +1070,8 @@ async fn post_attachment_v2(
headers: Headers, headers: Headers,
mut conn: DbConn, mut conn: DbConn,
) -> JsonResult { ) -> JsonResult {
let cipher = match Cipher::find_by_uuid(uuid, &mut conn).await { let Some(cipher) = Cipher::find_by_uuid(uuid, &mut conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { 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") err!("Attachment size can't be negative")
} }
let cipher = match Cipher::find_by_uuid(cipher_uuid, &mut conn).await { let Some(cipher) = Cipher::find_by_uuid(cipher_uuid, &mut conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await { 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 data = data.into_inner();
let user_uuid = headers.user.uuid; let user_uuid = headers.user.uuid;
if let Some(ref folder_id) = data.folder_id { if let Some(ref folder_uuid) = data.folder_id {
match Folder::find_by_uuid(folder_id, &mut conn).await { if Folder::find_by_uuid_and_user(folder_uuid, &user_uuid, &mut conn).await.is_none() {
Some(folder) => { err!("Invalid folder", "Folder does not exist or belongs to another user");
if folder.user_uuid != user_uuid {
err!("Folder is not owned by user")
}
}
None => err!("Folder doesn't exist"),
} }
} }
for uuid in data.ids { for uuid in data.ids {
let cipher = match Cipher::find_by_uuid(&uuid, &mut conn).await { let Some(cipher) = Cipher::find_by_uuid(&uuid, &mut conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_accessible_to_user(&user_uuid, &mut conn).await { if !cipher.is_accessible_to_user(&user_uuid, &mut conn).await {
@ -1667,9 +1645,8 @@ async fn _delete_cipher_by_uuid(
soft_delete: bool, soft_delete: bool,
nt: &Notify<'_>, nt: &Notify<'_>,
) -> EmptyResult { ) -> EmptyResult {
let mut cipher = match Cipher::find_by_uuid(uuid, conn).await { let Some(mut cipher) = Cipher::find_by_uuid(uuid, conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await { 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 { 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 { let Some(mut cipher) = Cipher::find_by_uuid(uuid, conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await { 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, conn: &mut DbConn,
nt: &Notify<'_>, nt: &Notify<'_>,
) -> EmptyResult { ) -> EmptyResult {
let attachment = match Attachment::find_by_id(attachment_id, conn).await { let Some(attachment) = Attachment::find_by_id(attachment_id, conn).await else {
Some(attachment) => attachment, err!("Attachment doesn't exist")
None => err!("Attachment doesn't exist"),
}; };
if attachment.cipher_uuid != uuid { if attachment.cipher_uuid != uuid {
err!("Attachment from other cipher") err!("Attachment from other cipher")
} }
let cipher = match Cipher::find_by_uuid(uuid, conn).await { let Some(cipher) = Cipher::find_by_uuid(uuid, conn).await else {
Some(cipher) => cipher, err!("Cipher doesn't exist")
None => err!("Cipher doesn't exist"),
}; };
if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await { if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn).await {

@ -137,11 +137,11 @@ async fn post_emergency_access(
let data: EmergencyAccessUpdateData = data.into_inner(); let data: EmergencyAccessUpdateData = data.into_inner();
let mut emergency_access = let Some(mut emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await
Some(emergency_access) => emergency_access, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
let new_type = match EmergencyAccessType::from_str(&data.r#type.into_string()) { let new_type = match EmergencyAccessType::from_str(&data.r#type.into_string()) {
Some(new_type) => new_type as i32, 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 { async fn resend_invite(emer_id: &str, headers: Headers, mut conn: DbConn) -> EmptyResult {
check_emergency_access_enabled()?; check_emergency_access_enabled()?;
let mut emergency_access = let Some(mut emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
if emergency_access.status != EmergencyAccessStatus::Invited as i32 { if emergency_access.status != EmergencyAccessStatus::Invited as i32 {
err!("The grantee user is already accepted or confirmed to the organization"); err!("The grantee user is already accepted or confirmed to the organization");
} }
let email = match emergency_access.email.clone() { let Some(email) = emergency_access.email.clone() else {
Some(email) => email, err!("Email not valid.")
None => err!("Email not valid."),
}; };
let grantee_user = match User::find_by_mail(&email, &mut conn).await { let Some(grantee_user) = User::find_by_mail(&email, &mut conn).await else {
Some(user) => user, err!("Grantee user not found.")
None => err!("Grantee user not found."),
}; };
let grantor_user = headers.user; 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. // 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. // The uuid of the grantee gets stored once accepted.
let mut emergency_access = let Some(mut emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantee_email(emer_id, &headers.user.email, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantee_email(emer_id, &headers.user.email, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
// get grantor user to send Accepted email // get grantor user to send Accepted email
let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
Some(user) => user, err!("Grantor user not found.")
None => err!("Grantor user not found."),
}; };
if emer_id == claims.emer_id if emer_id == claims.emer_id
@ -403,11 +400,11 @@ async fn confirm_emergency_access(
let data: ConfirmData = data.into_inner(); let data: ConfirmData = data.into_inner();
let key = data.key; let key = data.key;
let mut emergency_access = let Some(mut emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &confirming_user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &confirming_user.uuid, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
if emergency_access.status != EmergencyAccessStatus::Accepted as i32 if emergency_access.status != EmergencyAccessStatus::Accepted as i32
|| emergency_access.grantor_uuid != confirming_user.uuid || emergency_access.grantor_uuid != confirming_user.uuid
@ -415,15 +412,13 @@ async fn confirm_emergency_access(
err!("Emergency access not valid.") err!("Emergency access not valid.")
} }
let grantor_user = match User::find_by_uuid(&confirming_user.uuid, &mut conn).await { let Some(grantor_user) = User::find_by_uuid(&confirming_user.uuid, &mut conn).await else {
Some(user) => user, err!("Grantor user not found.")
None => err!("Grantor user not found."),
}; };
if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() { if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() {
let grantee_user = match User::find_by_uuid(grantee_uuid, &mut conn).await { let Some(grantee_user) = User::find_by_uuid(grantee_uuid, &mut conn).await else {
Some(user) => user, err!("Grantee user not found.")
None => err!("Grantee user not found."),
}; };
emergency_access.status = EmergencyAccessStatus::Confirmed as i32; 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()?; check_emergency_access_enabled()?;
let initiating_user = headers.user; let initiating_user = headers.user;
let mut emergency_access = let Some(mut emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &initiating_user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &initiating_user.uuid, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
if emergency_access.status != EmergencyAccessStatus::Confirmed as i32 { if emergency_access.status != EmergencyAccessStatus::Confirmed as i32 {
err!("Emergency access not valid.") err!("Emergency access not valid.")
} }
let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
Some(user) => user, err!("Grantor user not found.")
None => err!("Grantor user not found."),
}; };
let now = Utc::now().naive_utc(); 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 { async fn approve_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
check_emergency_access_enabled()?; check_emergency_access_enabled()?;
let mut emergency_access = let Some(mut emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32 { if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32 {
err!("Emergency access not valid.") err!("Emergency access not valid.")
} }
let grantor_user = match User::find_by_uuid(&headers.user.uuid, &mut conn).await { let Some(grantor_user) = User::find_by_uuid(&headers.user.uuid, &mut conn).await else {
Some(user) => user, err!("Grantor user not found.")
None => err!("Grantor user not found."),
}; };
if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() { if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() {
let grantee_user = match User::find_by_uuid(grantee_uuid, &mut conn).await { let Some(grantee_user) = User::find_by_uuid(grantee_uuid, &mut conn).await else {
Some(user) => user, err!("Grantee user not found.")
None => err!("Grantee user not found."),
}; };
emergency_access.status = EmergencyAccessStatus::RecoveryApproved as i32; 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 { async fn reject_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
check_emergency_access_enabled()?; check_emergency_access_enabled()?;
let mut emergency_access = let Some(mut emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantor_uuid(emer_id, &headers.user.uuid, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32 if emergency_access.status != EmergencyAccessStatus::RecoveryInitiated as i32
&& emergency_access.status != EmergencyAccessStatus::RecoveryApproved 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() { if let Some(grantee_uuid) = emergency_access.grantee_uuid.as_ref() {
let grantee_user = match User::find_by_uuid(grantee_uuid, &mut conn).await { let Some(grantee_user) = User::find_by_uuid(grantee_uuid, &mut conn).await else {
Some(user) => user, err!("Grantee user not found.")
None => err!("Grantee user not found."),
}; };
emergency_access.status = EmergencyAccessStatus::Confirmed as i32; 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 { async fn view_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
check_emergency_access_enabled()?; check_emergency_access_enabled()?;
let emergency_access = let Some(emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &headers.user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &headers.user.uuid, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
if !is_valid_request(&emergency_access, &headers.user.uuid, EmergencyAccessType::View) { if !is_valid_request(&emergency_access, &headers.user.uuid, EmergencyAccessType::View) {
err!("Emergency access not valid.") 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()?; check_emergency_access_enabled()?;
let requesting_user = headers.user; let requesting_user = headers.user;
let emergency_access = let Some(emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) { if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) {
err!("Emergency access not valid.") err!("Emergency access not valid.")
} }
let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
Some(user) => user, err!("Grantor user not found.")
None => err!("Grantor user not found."),
}; };
let result = json!({ let result = json!({
@ -650,19 +640,18 @@ async fn password_emergency_access(
//let key = &data.Key; //let key = &data.Key;
let requesting_user = headers.user; let requesting_user = headers.user;
let emergency_access = let Some(emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) { if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) {
err!("Emergency access not valid.") err!("Emergency access not valid.")
} }
let mut grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { let Some(mut grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
Some(user) => user, err!("Grantor user not found.")
None => err!("Grantor user not found."),
}; };
// change grantor_user password // change grantor_user password
@ -686,19 +675,18 @@ async fn password_emergency_access(
#[get("/emergency-access/<emer_id>/policies")] #[get("/emergency-access/<emer_id>/policies")]
async fn policies_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult { async fn policies_emergency_access(emer_id: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
let requesting_user = headers.user; let requesting_user = headers.user;
let emergency_access = let Some(emergency_access) =
match EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await { EmergencyAccess::find_by_uuid_and_grantee_uuid(emer_id, &requesting_user.uuid, &mut conn).await
Some(emer) => emer, else {
None => err!("Emergency access not valid."), err!("Emergency access not valid.")
}; };
if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) { if !is_valid_request(&emergency_access, &requesting_user.uuid, EmergencyAccessType::Takeover) {
err!("Emergency access not valid.") err!("Emergency access not valid.")
} }
let grantor_user = match User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await { let Some(grantor_user) = User::find_by_uuid(&emergency_access.grantor_uuid, &mut conn).await else {
Some(user) => user, err!("Grantor user not found.")
None => err!("Grantor user not found."),
}; };
let policies = OrgPolicy::find_confirmed_by_user(&grantor_user.uuid, &mut conn); let policies = OrgPolicy::find_confirmed_by_user(&grantor_user.uuid, &mut conn);

@ -25,16 +25,10 @@ async fn get_folders(headers: Headers, mut conn: DbConn) -> Json<Value> {
#[get("/folders/<uuid>")] #[get("/folders/<uuid>")]
async fn get_folder(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult { async fn get_folder(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
let folder = match Folder::find_by_uuid(uuid, &mut conn).await { match Folder::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await {
Some(folder) => folder, Some(folder) => Ok(Json(folder.to_json())),
_ => err!("Invalid folder"), _ => 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")
} }
Ok(Json(folder.to_json()))
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -71,15 +65,10 @@ async fn put_folder(
) -> JsonResult { ) -> JsonResult {
let data: FolderData = data.into_inner(); let data: FolderData = data.into_inner();
let mut folder = match Folder::find_by_uuid(uuid, &mut conn).await { let Some(mut folder) = Folder::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
Some(folder) => folder, err!("Invalid folder", "Folder does not exist or belongs to another user")
_ => err!("Invalid folder"),
}; };
if folder.user_uuid != headers.user.uuid {
err!("Folder belongs to another user")
}
folder.name = data.name; folder.name = data.name;
folder.save(&mut conn).await?; 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>")] #[delete("/folders/<uuid>")]
async fn delete_folder(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { 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 { let Some(folder) = Folder::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
Some(folder) => folder, err!("Invalid folder", "Folder does not exist or belongs to another user")
_ => err!("Invalid folder"),
}; };
if folder.user_uuid != headers.user.uuid {
err!("Folder belongs to another user")
}
// Delete the actual folder entry // Delete the actual folder entry
folder.delete(&mut conn).await?; folder.delete(&mut conn).await?;

@ -267,9 +267,8 @@ async fn post_organization(
) -> JsonResult { ) -> JsonResult {
let data: OrganizationUpdateData = data.into_inner(); let data: OrganizationUpdateData = data.into_inner();
let mut org = match Organization::find_by_uuid(org_id, &mut conn).await { let Some(mut org) = Organization::find_by_uuid(org_id, &mut conn).await else {
Some(organization) => organization, err!("Can't find organization details")
None => err!("Can't find organization details"),
}; };
org.name = data.name; 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 { async fn get_org_collections_details(org_id: &str, headers: ManagerHeadersLoose, mut conn: DbConn) -> JsonResult {
let mut data = Vec::new(); let mut data = Vec::new();
let user_org = match UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await { let Some(user_org) = UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await else {
Some(u) => u, err!("User is not part of organization")
None => err!("User is not part of organization"),
}; };
// get all collection memberships for the current organization // get all collection memberships for the current organization
@ -387,9 +385,8 @@ async fn post_organization_collections(
) -> JsonResult { ) -> JsonResult {
let data: NewCollectionData = data.into_inner(); let data: NewCollectionData = data.into_inner();
let org = match Organization::find_by_uuid(org_id, &mut conn).await { let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else {
Some(organization) => organization, err!("Can't find organization details")
None => err!("Can't find organization details"),
}; };
let collection = Collection::new(org.uuid, data.name, data.external_id); 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 { for user in data.users {
let org_user = match UserOrganization::find_by_uuid(&user.id, &mut conn).await { let Some(org_user) = UserOrganization::find_by_uuid_and_org(&user.id, org_id, &mut conn).await else {
Some(u) => u, err!("User is not part of organization")
None => err!("User is not part of organization"),
}; };
if org_user.access_all { if org_user.access_all {
@ -454,20 +450,14 @@ async fn post_organization_collection_update(
) -> JsonResult { ) -> JsonResult {
let data: NewCollectionData = data.into_inner(); let data: NewCollectionData = data.into_inner();
let org = match Organization::find_by_uuid(org_id, &mut conn).await { if Organization::find_by_uuid(org_id, &mut conn).await.is_none() {
Some(organization) => organization, err!("Can't find organization details")
None => err!("Can't find organization details"),
}; };
let mut collection = match Collection::find_by_uuid(col_id, &mut conn).await { let Some(mut collection) = Collection::find_by_uuid_and_org(col_id, org_id, &mut conn).await else {
Some(collection) => collection, err!("Collection not found")
None => err!("Collection not found"),
}; };
if collection.org_uuid != org.uuid {
err!("Collection is not owned by organization");
}
collection.name = data.name; collection.name = data.name;
collection.external_id = match data.external_id { collection.external_id = match data.external_id {
Some(external_id) if !external_id.trim().is_empty() => Some(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?; CollectionUser::delete_all_by_collection(col_id, &mut conn).await?;
for user in data.users { for user in data.users {
let org_user = match UserOrganization::find_by_uuid(&user.id, &mut conn).await { let Some(org_user) = UserOrganization::find_by_uuid_and_org(&user.id, org_id, &mut conn).await else {
Some(u) => u, err!("User is not part of organization")
None => err!("User is not part of organization"),
}; };
if org_user.access_all { if org_user.access_all {
@ -521,15 +510,8 @@ async fn delete_organization_collection_user(
_headers: AdminHeaders, _headers: AdminHeaders,
mut conn: DbConn, mut conn: DbConn,
) -> EmptyResult { ) -> EmptyResult {
let collection = match Collection::find_by_uuid(col_id, &mut conn).await { let Some(collection) = Collection::find_by_uuid_and_org(col_id, org_id, &mut conn).await else {
None => err!("Collection not found"), err!("Collection not found", "Collection does not exist or does not belong to this organization")
Some(collection) => {
if collection.org_uuid == org_id {
collection
} else {
err!("Collection and Organization id do not match")
}
}
}; };
match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await { 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, headers: &ManagerHeaders,
conn: &mut DbConn, conn: &mut DbConn,
) -> EmptyResult { ) -> EmptyResult {
match Collection::find_by_uuid(col_id, conn).await { let Some(collection) = Collection::find_by_uuid_and_org(col_id, org_id, conn).await else {
None => err!("Collection not found"), err!("Collection not found", "Collection does not exist or does not belong to this organization")
Some(collection) => { };
if collection.org_uuid == org_id { log_event(
log_event( EventType::CollectionDeleted as i32,
EventType::CollectionDeleted as i32, &collection.uuid,
&collection.uuid, org_id,
org_id, &headers.user.uuid,
&headers.user.uuid, headers.device.atype,
headers.device.atype, &headers.ip.ip,
&headers.ip.ip, conn,
conn, )
) .await;
.await; collection.delete(conn).await
collection.delete(conn).await
} else {
err!("Collection and Organization id do not match")
}
}
}
} }
#[delete("/organizations/<org_id>/collections/<col_id>")] #[delete("/organizations/<org_id>/collections/<col_id>")]
@ -601,12 +577,11 @@ struct DeleteCollectionData {
org_id: String, 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( async fn post_organization_collection_delete(
org_id: &str, org_id: &str,
col_id: &str, col_id: &str,
headers: ManagerHeaders, headers: ManagerHeaders,
_data: Json<DeleteCollectionData>,
mut conn: DbConn, mut conn: DbConn,
) -> EmptyResult { ) -> EmptyResult {
_delete_organization_collection(org_id, col_id, &headers, &mut conn).await _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") 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 { let Some(user_org) = UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await
Some(u) => u, else {
None => err!("User is not part of organization"), err!("User is not part of organization")
}; };
let groups: Vec<Value> = if CONFIG.org_groups_enabled() { 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")] #[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 { 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 // 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 { let Some(collection) = Collection::find_by_uuid_and_org(coll_id, org_id, &mut conn).await else {
None => err!("Collection not found in Organization"), err!("Collection not found in Organization")
Some(collection) => collection,
}; };
let mut user_list = Vec::new(); 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) // And then add all the received ones (except if the user has access_all)
for d in data.iter() { for d in data.iter() {
let user = match UserOrganization::find_by_uuid(&d.id, &mut conn).await { let Some(user) = UserOrganization::find_by_uuid_and_org(&d.id, org_id, &mut conn).await else {
Some(u) => u, err!("User is not part of organization")
None => err!("User is not part of organization"),
}; };
if user.access_all { 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 { 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 { let Some(user_org) = UserOrganization::find_by_uuid_and_org(user_org, org_id, conn).await else {
Some(user_org) => user_org, err!("The user hasn't been invited to the organization.")
None => err!("The user hasn't been invited to the organization."),
}; };
if user_org.status != UserOrgStatus::Invited as i32 { if user_org.status != UserOrgStatus::Invited as i32 {
err!("The user is already accepted or confirmed to the organization") err!("The user is already accepted or confirmed to the organization")
} }
let user = match User::find_by_uuid(&user_org.user_uuid, conn).await { let Some(user) = User::find_by_uuid(&user_org.user_uuid, conn).await else {
Some(user) => user, err!("User not found.")
None => err!("User not found."),
}; };
if !CONFIG.invitations_allowed() && user.password_hash.is_empty() { if !CONFIG.invitations_allowed() && user.password_hash.is_empty() {
@ -1059,20 +1030,25 @@ struct AcceptData {
reset_password_key: Option<String>, reset_password_key: Option<String>,
} }
#[post("/organizations/<org_id>/users/<_org_user_id>/accept", data = "<data>")] #[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 { 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 // 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 data: AcceptData = data.into_inner();
let claims = decode_invite(&data.token)?; 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 { match User::find_by_mail(&claims.email, &mut conn).await {
Some(user) => { Some(user) => {
Invitation::take(&claims.email, &mut conn).await; Invitation::take(&claims.email, &mut conn).await;
if let (Some(user_org), Some(org)) = (&claims.user_org_id, &claims.org_id) { 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 { let Some(mut user_org) = UserOrganization::find_by_uuid_and_org(user_org, org, &mut conn).await else {
Some(user_org) => user_org, err!("Error accepting the invitation")
None => err!("Error accepting the invitation"),
}; };
if user_org.status != UserOrgStatus::Invited as i32 { 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"); 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 { let Some(mut user_to_confirm) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await else {
Some(user) => user, err!("The specified user isn't a member of the organization")
None => err!("The specified user isn't a member of the organization"),
}; };
if user_to_confirm.atype != UserOrgType::User && headers.org_user_type != UserOrgType::Owner { if user_to_confirm.atype != UserOrgType::User && headers.org_user_type != UserOrgType::Owner {
@ -1287,9 +1262,8 @@ async fn get_user(
_headers: AdminHeaders, _headers: AdminHeaders,
mut conn: DbConn, mut conn: DbConn,
) -> JsonResult { ) -> JsonResult {
let user = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await { let Some(user) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await else {
Some(user) => user, err!("The specified user isn't a member of the organization")
None => err!("The specified user isn't a member of the organization"),
}; };
// In this case, when groups are requested we also need to include collections. // In this case, when groups are requested we also need to include collections.
@ -1331,14 +1305,12 @@ async fn edit_user(
) -> EmptyResult { ) -> EmptyResult {
let data: EditUserData = data.into_inner(); let data: EditUserData = data.into_inner();
let new_type = match UserOrgType::from_str(&data.r#type.into_string()) { let Some(new_type) = UserOrgType::from_str(&data.r#type.into_string()) else {
Some(new_type) => new_type, err!("Invalid type")
None => err!("Invalid type"),
}; };
let mut user_to_edit = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await { let Some(mut user_to_edit) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await else {
Some(user) => user, err!("The specified user isn't member of the organization")
None => err!("The specified user isn't member of the organization"),
}; };
if new_type != user_to_edit.atype if new_type != user_to_edit.atype
@ -1490,9 +1462,8 @@ async fn _delete_user(
conn: &mut DbConn, conn: &mut DbConn,
nt: &Notify<'_>, nt: &Notify<'_>,
) -> EmptyResult { ) -> EmptyResult {
let user_to_delete = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await { let Some(user_to_delete) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await else {
Some(user) => user, err!("User to delete isn't member of the organization")
None => err!("User to delete isn't member of the organization"),
}; };
if user_to_delete.atype != UserOrgType::User && headers.org_user_type != UserOrgType::Owner { 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 = decode_invite(token)?;
let invite_org_id = match invite.org_id { let Some(invite_org_id) = invite.org_id else {
Some(invite_org_id) => invite_org_id, err!("Invalid token")
None => err!("Invalid token"),
}; };
if invite_org_id != org_id { 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>")] #[get("/organizations/<org_id>/policies/<pol_type>")]
async fn get_policy(org_id: &str, pol_type: i32, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { 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) { let Some(pol_type_enum) = OrgPolicyType::from_i32(pol_type) else {
Some(pt) => pt, err!("Invalid or unsupported policy type")
None => err!("Invalid or unsupported policy type"),
}; };
let policy = match OrgPolicy::find_by_org_and_type(org_id, pol_type_enum, &mut conn).await { 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 { ) -> JsonResult {
let data: PolicyData = data.into_inner(); let data: PolicyData = data.into_inner();
let pol_type_enum = match OrgPolicyType::from_i32(pol_type) { let Some(pol_type_enum) = OrgPolicyType::from_i32(pol_type) else {
Some(pt) => pt, err!("Invalid or unsupported policy type")
None => err!("Invalid or unsupported policy type"),
}; };
// Bitwarden only allows the Reset Password policy when Single Org policy is enabled // 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"); err!("Group support is disabled");
} }
let group = match Group::find_by_uuid(group_id, &mut conn).await { let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await else {
Some(group) => group, err!("Group not found", "Group uuid is invalid or does not belong to the organization")
None => err!("Group not found"),
}; };
let group_request = data.into_inner(); let group_request = data.into_inner();
@ -2502,15 +2469,14 @@ async fn add_update_group(
}))) })))
} }
#[get("/organizations/<_org_id>/groups/<group_id>/details")] #[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 { async fn get_group_details(org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
if !CONFIG.org_groups_enabled() { if !CONFIG.org_groups_enabled() {
err!("Group support is disabled"); err!("Group support is disabled");
} }
let group = match Group::find_by_uuid(group_id, &mut conn).await { let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await else {
Some(group) => group, err!("Group not found", "Group uuid is invalid or does not belong to the organization")
_ => err!("Group could not be found!"),
}; };
Ok(Json(group.to_json_details(&mut conn).await)) 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"); err!("Group support is disabled");
} }
let group = match Group::find_by_uuid(group_id, conn).await { let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, conn).await else {
Some(group) => group, err!("Group not found", "Group uuid is invalid or does not belong to the organization")
_ => err!("Group not found"),
}; };
log_event( log_event(
@ -2569,29 +2534,27 @@ async fn bulk_delete_groups(
Ok(()) Ok(())
} }
#[get("/organizations/<_org_id>/groups/<group_id>")] #[get("/organizations/<org_id>/groups/<group_id>")]
async fn get_group(_org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult { async fn get_group(org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
if !CONFIG.org_groups_enabled() { if !CONFIG.org_groups_enabled() {
err!("Group support is disabled"); err!("Group support is disabled");
} }
let group = match Group::find_by_uuid(group_id, &mut conn).await { let Some(group) = Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await else {
Some(group) => group, err!("Group not found", "Group uuid is invalid or does not belong to the organization")
_ => err!("Group not found"),
}; };
Ok(Json(group.to_json())) Ok(Json(group.to_json()))
} }
#[get("/organizations/<_org_id>/groups/<group_id>/users")] #[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 { async fn get_group_users(org_id: &str, group_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
if !CONFIG.org_groups_enabled() { if !CONFIG.org_groups_enabled() {
err!("Group support is disabled"); err!("Group support is disabled");
} }
match Group::find_by_uuid(group_id, &mut conn).await { if Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await.is_none() {
Some(_) => { /* Do nothing */ } err!("Group could not be found!", "Group uuid is invalid or does not belong to the organization")
_ => err!("Group could not be found!"),
}; };
let group_users: Vec<String> = GroupUser::find_by_group(group_id, &mut conn) 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"); err!("Group support is disabled");
} }
match Group::find_by_uuid(group_id, &mut conn).await { if Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await.is_none() {
Some(_) => { /* Do nothing */ } err!("Group could not be found!", "Group uuid is invalid or does not belong to the organization")
_ => err!("Group could not be found!"),
}; };
GroupUser::delete_all_by_group(group_id, &mut conn).await?; GroupUser::delete_all_by_group(group_id, &mut conn).await?;
@ -2642,15 +2604,14 @@ async fn put_group_users(
Ok(()) Ok(())
} }
#[get("/organizations/<_org_id>/users/<user_id>/groups")] #[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 { async fn get_user_groups(org_id: &str, user_id: &str, _headers: AdminHeaders, mut conn: DbConn) -> JsonResult {
if !CONFIG.org_groups_enabled() { if !CONFIG.org_groups_enabled() {
err!("Group support is disabled"); err!("Group support is disabled");
} }
match UserOrganization::find_by_uuid(user_id, &mut conn).await { if UserOrganization::find_by_uuid_and_org(user_id, org_id, &mut conn).await.is_none() {
Some(_) => { /* Do nothing */ } err!("User could not be found!")
_ => err!("User could not be found!"),
}; };
let user_groups: Vec<String> = let user_groups: Vec<String> =
@ -2688,13 +2649,8 @@ async fn put_user_groups(
err!("Group support is disabled"); err!("Group support is disabled");
} }
let user_org = match UserOrganization::find_by_uuid(org_user_id, &mut conn).await { if UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await.is_none() {
Some(uo) => uo, err!("User could not be found or does not belong to the organization.");
_ => err!("User could not be found!"),
};
if user_org.org_uuid != org_id {
err!("Group doesn't belong to organization");
} }
GroupUser::delete_all_by_user(org_user_id, &mut conn).await?; 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"); err!("Group support is disabled");
} }
let user_org = match UserOrganization::find_by_uuid(org_user_id, &mut conn).await { if UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await.is_none() {
Some(uo) => uo, err!("User could not be found or does not belong to the organization.");
_ => err!("User could not be found!"),
};
if user_org.org_uuid != org_id {
err!("User doesn't belong to organization");
} }
let group = match Group::find_by_uuid(group_id, &mut conn).await { if Group::find_by_uuid_and_org(group_id, org_id, &mut conn).await.is_none() {
Some(g) => g, err!("Group could not be found or does not belong to the organization.");
_ => err!("Group could not be found!"),
};
if group.organizations_uuid != org_id {
err!("Group doesn't belong to organization");
} }
log_event( log_event(
@ -2794,9 +2740,8 @@ struct OrganizationUserResetPasswordRequest {
// Just add it here in case they will // Just add it here in case they will
#[get("/organizations/<org_id>/public-key")] #[get("/organizations/<org_id>/public-key")]
async fn get_organization_public_key(org_id: &str, _headers: Headers, mut conn: DbConn) -> JsonResult { 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 { let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else {
Some(organization) => organization, err!("Organization not found")
None => err!("Organization not found"),
}; };
Ok(Json(json!({ Ok(Json(json!({
@ -2821,19 +2766,16 @@ async fn put_reset_password(
mut conn: DbConn, mut conn: DbConn,
nt: Notify<'_>, nt: Notify<'_>,
) -> EmptyResult { ) -> EmptyResult {
let org = match Organization::find_by_uuid(org_id, &mut conn).await { let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else {
Some(org) => org, err!("Required organization not found")
None => err!("Required organization not found"),
}; };
let org_user = match UserOrganization::find_by_uuid_and_org(org_user_id, &org.uuid, &mut conn).await { let Some(org_user) = UserOrganization::find_by_uuid_and_org(org_user_id, &org.uuid, &mut conn).await else {
Some(user) => user, err!("User to reset isn't member of required organization")
None => err!("User to reset isn't member of required organization"),
}; };
let user = match User::find_by_uuid(&org_user.user_uuid, &mut conn).await { let Some(user) = User::find_by_uuid(&org_user.user_uuid, &mut conn).await else {
Some(user) => user, err!("User not found")
None => err!("User not found"),
}; };
check_reset_password_applicable_and_permissions(org_id, org_user_id, &headers, &mut conn).await?; 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, headers: AdminHeaders,
mut conn: DbConn, mut conn: DbConn,
) -> JsonResult { ) -> JsonResult {
let org = match Organization::find_by_uuid(org_id, &mut conn).await { let Some(org) = Organization::find_by_uuid(org_id, &mut conn).await else {
Some(org) => org, err!("Required organization not found")
None => err!("Required organization not found"),
}; };
let org_user = match UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await { let Some(org_user) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, &mut conn).await else {
Some(user) => user, err!("User to reset isn't member of required organization")
None => err!("User to reset isn't member of required organization"),
}; };
let user = match User::find_by_uuid(&org_user.user_uuid, &mut conn).await { let Some(user) = User::find_by_uuid(&org_user.user_uuid, &mut conn).await else {
Some(user) => user, err!("User not found")
None => err!("User not found"),
}; };
check_reset_password_applicable_and_permissions(org_id, org_user_id, &headers, &mut conn).await?; 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 { ) -> EmptyResult {
check_reset_password_applicable(org_id, conn).await?; 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 { let Some(target_user) = UserOrganization::find_by_uuid_and_org(org_user_id, org_id, conn).await else {
Some(user) => user, err!("Reset target user not found")
None => err!("Reset target user not found"),
}; };
// Resetting user must be higher/equal to user to reset // 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."); 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 { let Some(policy) = OrgPolicy::find_by_org_and_type(org_id, OrgPolicyType::ResetPassword, conn).await else {
Some(p) => p, err!("Policy not found")
None => err!("Policy not found"),
}; };
if !policy.enabled { if !policy.enabled {
@ -2956,9 +2893,8 @@ async fn put_reset_password_enrollment(
data: Json<OrganizationUserResetPasswordEnrollmentRequest>, data: Json<OrganizationUserResetPasswordEnrollmentRequest>,
mut conn: DbConn, mut conn: DbConn,
) -> EmptyResult { ) -> EmptyResult {
let mut org_user = match UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await { let Some(mut org_user) = UserOrganization::find_by_user_and_org(&headers.user.uuid, org_id, &mut conn).await else {
Some(u) => u, err!("User to enroll isn't member of required organization")
None => err!("User to enroll isn't member of required organization"),
}; };
check_reset_password_applicable(org_id, &mut conn).await?; check_reset_password_applicable(org_id, &mut conn).await?;

@ -203,9 +203,8 @@ impl<'r> FromRequest<'r> for PublicToken {
None => err_handler!("No access token provided"), None => err_handler!("No access token provided"),
}; };
// Check JWT token is valid and get device and user from it // Check JWT token is valid and get device and user from it
let claims = match auth::decode_api_org(access_token) { let Ok(claims) = auth::decode_api_org(access_token) else {
Ok(claims) => claims, err_handler!("Invalid claim")
Err(_) => err_handler!("Invalid claim"),
}; };
// Check if time is between claims.nbf and claims.exp // Check if time is between claims.nbf and claims.exp
let time_now = Utc::now().timestamp(); let time_now = Utc::now().timestamp();
@ -227,13 +226,11 @@ impl<'r> FromRequest<'r> for PublicToken {
Outcome::Success(conn) => conn, Outcome::Success(conn) => conn,
_ => err_handler!("Error getting DB"), _ => err_handler!("Error getting DB"),
}; };
let org_uuid = match claims.client_id.strip_prefix("organization.") { let Some(org_uuid) = claims.client_id.strip_prefix("organization.") else {
Some(uuid) => uuid, err_handler!("Malformed client_id")
None => err_handler!("Malformed client_id"),
}; };
let org_api_key = match OrganizationApiKey::find_by_org_uuid(org_uuid, &conn).await { let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(org_uuid, &conn).await else {
Some(org_api_key) => org_api_key, err_handler!("Invalid client_id")
None => err_handler!("Invalid client_id"),
}; };
if org_api_key.org_uuid != claims.client_sub { if org_api_key.org_uuid != claims.client_sub {
err_handler!("Token not issued for this org"); err_handler!("Token not issued for this org");

@ -159,16 +159,10 @@ async fn get_sends(headers: Headers, mut conn: DbConn) -> Json<Value> {
#[get("/sends/<uuid>")] #[get("/sends/<uuid>")]
async fn get_send(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult { async fn get_send(uuid: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
let send = match Send::find_by_uuid(uuid, &mut conn).await { match Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await {
Some(send) => send, Some(send) => Ok(Json(send.to_json())),
None => err!("Send not found"), None => err!("Send not found", "Invalid uuid or does not belong to user"),
};
if send.user_uuid.as_ref() != Some(&headers.user.uuid) {
err!("Send is not owned by user")
} }
Ok(Json(send.to_json()))
} }
#[post("/sends", data = "<data>")] #[post("/sends", data = "<data>")]
@ -371,22 +365,14 @@ async fn post_send_file_v2_data(
let mut data = data.into_inner(); let mut data = data.into_inner();
let Some(send) = Send::find_by_uuid(send_uuid, &mut conn).await else { 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.") err!("Send not found. Unable to save the file.", "Invalid uuid or does not belong to user.")
}; };
if send.atype != SendType::File as i32 { if send.atype != SendType::File as i32 {
err!("Send is not a file type send."); 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 { let Ok(send_data) = serde_json::from_str::<SendFileData>(&send.data) else {
err!("Unable to decode send data as json.") err!("Unable to decode send data as json.")
}; };
@ -456,9 +442,8 @@ async fn post_access(
ip: ClientIp, ip: ClientIp,
nt: Notify<'_>, nt: Notify<'_>,
) -> JsonResult { ) -> JsonResult {
let mut send = match Send::find_by_access_id(access_id, &mut conn).await { let Some(mut send) = Send::find_by_access_id(access_id, &mut conn).await else {
Some(s) => s, err_code!(SEND_INACCESSIBLE_MSG, 404)
None => err_code!(SEND_INACCESSIBLE_MSG, 404),
}; };
if let Some(max_access_count) = send.max_access_count { if let Some(max_access_count) = send.max_access_count {
@ -517,9 +502,8 @@ async fn post_access_file(
mut conn: DbConn, mut conn: DbConn,
nt: Notify<'_>, nt: Notify<'_>,
) -> JsonResult { ) -> JsonResult {
let mut send = match Send::find_by_uuid(send_id, &mut conn).await { let Some(mut send) = Send::find_by_uuid(send_id, &mut conn).await else {
Some(s) => s, err_code!(SEND_INACCESSIBLE_MSG, 404)
None => err_code!(SEND_INACCESSIBLE_MSG, 404),
}; };
if let Some(max_access_count) = send.max_access_count { 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 None
} }
#[put("/sends/<id>", data = "<data>")] #[put("/sends/<uuid>", data = "<data>")]
async fn put_send(id: &str, data: Json<SendData>, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { 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?; enforce_disable_send_policy(&headers, &mut conn).await?;
let data: SendData = data.into_inner(); let data: SendData = data.into_inner();
enforce_disable_hide_email_policy(&data, &headers, &mut conn).await?; enforce_disable_hide_email_policy(&data, &headers, &mut conn).await?;
let mut send = match Send::find_by_uuid(id, &mut conn).await { let Some(mut send) = Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
Some(s) => s, err!("Send not found", "Send uuid is invalid or does not belong to user")
None => err!("Send not found"),
}; };
update_send_from_data(&mut send, data, &headers, &mut conn, &nt, UpdateType::SyncSendUpdate).await?; 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(()) Ok(())
} }
#[delete("/sends/<id>")] #[delete("/sends/<uuid>")]
async fn delete_send(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult { async fn delete_send(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> EmptyResult {
let send = match Send::find_by_uuid(id, &mut conn).await { let Some(send) = Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
Some(s) => s, err!("Send not found", "Invalid send uuid, or does not belong to user")
None => err!("Send not found"),
}; };
if send.user_uuid.as_ref() != Some(&headers.user.uuid) {
err!("Send is not owned by user")
}
send.delete(&mut conn).await?; send.delete(&mut conn).await?;
nt.send_send_update( nt.send_send_update(
UpdateType::SyncSendDelete, UpdateType::SyncSendDelete,
@ -681,19 +659,14 @@ async fn delete_send(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_
Ok(()) Ok(())
} }
#[put("/sends/<id>/remove-password")] #[put("/sends/<uuid>/remove-password")]
async fn put_remove_password(id: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult { async fn put_remove_password(uuid: &str, headers: Headers, mut conn: DbConn, nt: Notify<'_>) -> JsonResult {
enforce_disable_send_policy(&headers, &mut conn).await?; enforce_disable_send_policy(&headers, &mut conn).await?;
let mut send = match Send::find_by_uuid(id, &mut conn).await { let Some(mut send) = Send::find_by_uuid_and_user(uuid, &headers.user.uuid, &mut conn).await else {
Some(s) => s, err!("Send not found", "Invalid send uuid, or does not belong to user")
None => err!("Send not found"),
}; };
if send.user_uuid.as_ref() != Some(&headers.user.uuid) {
err!("Send is not owned by user")
}
send.set_password(None); send.set_password(None);
send.save(&mut conn).await?; send.save(&mut conn).await?;
nt.send_send_update( nt.send_send_update(

@ -117,9 +117,8 @@ pub async fn validate_totp_code(
) -> EmptyResult { ) -> EmptyResult {
use totp_lite::{totp_custom, Sha1}; use totp_lite::{totp_custom, Sha1};
let decoded_secret = match BASE32.decode(secret.as_bytes()) { let Ok(decoded_secret) = BASE32.decode(secret.as_bytes()) else {
Ok(s) => s, err!("Invalid TOTP secret")
Err(_) => err!("Invalid TOTP secret"),
}; };
let mut twofactor = let mut twofactor =

@ -232,9 +232,8 @@ async fn get_user_duo_data(uuid: &str, conn: &mut DbConn) -> DuoStatus {
let type_ = TwoFactorType::Duo as i32; let type_ = TwoFactorType::Duo as i32;
// If the user doesn't have an entry, disabled // If the user doesn't have an entry, disabled
let twofactor = match TwoFactor::find_by_user_and_type(uuid, type_, conn).await { let Some(twofactor) = TwoFactor::find_by_user_and_type(uuid, type_, conn).await else {
Some(t) => t, return DuoStatus::Disabled(DuoData::global().is_some());
None => return DuoStatus::Disabled(DuoData::global().is_some()),
}; };
// If the user has the required values, we use those // 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") err!("Prefixes don't match")
} }
let cookie_vec = match BASE64.decode(u_b64.as_bytes()) { let Ok(cookie_vec) = BASE64.decode(u_b64.as_bytes()) else {
Ok(c) => c, err!("Invalid Duo cookie encoding")
Err(_) => err!("Invalid Duo cookie encoding"),
}; };
let cookie = match String::from_utf8(cookie_vec) { let Ok(cookie) = String::from_utf8(cookie_vec) else {
Ok(c) => c, err!("Invalid Duo cookie encoding")
Err(_) => err!("Invalid Duo cookie encoding"),
}; };
let cookie_split: Vec<&str> = cookie.split('|').collect(); let cookie_split: Vec<&str> = cookie.split('|').collect();

@ -40,9 +40,8 @@ async fn send_email_login(data: Json<SendEmailLoginData>, mut conn: DbConn) -> E
use crate::db::models::User; use crate::db::models::User;
// Get the user // Get the user
let user = match User::find_by_mail(&data.email, &mut conn).await { let Some(user) = User::find_by_mail(&data.email, &mut conn).await else {
Some(user) => user, err!("Username or password is incorrect. Try again.")
None => err!("Username or password is incorrect. Try again."),
}; };
// Check password // 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 mut email_data = EmailTokenData::from_json(&twofactor.data)?;
let issued_token = match &email_data.last_token { let Some(issued_token) = &email_data.last_token else {
Some(t) => t, err!("No token available")
_ => err!("No token available"),
}; };
if !crypto::ct_eq(issued_token, data.token) { 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) let mut twofactor = TwoFactor::find_by_user_and_type(user_uuid, TwoFactorType::Email as i32, conn)
.await .await
.map_res("Two factor not found")?; .map_res("Two factor not found")?;
let issued_token = match &email_data.last_token { let Some(issued_token) = &email_data.last_token else {
Some(t) => t, err!(
_ => err!(
"No token available", "No token available",
ErrorEvent { ErrorEvent {
event: EventType::UserFailedLogIn2fa event: EventType::UserFailedLogIn2fa
} }
), )
}; };
if !crypto::ct_eq(issued_token, token) { if !crypto::ct_eq(issued_token, token) {

@ -85,9 +85,8 @@ async fn recover(data: Json<RecoverTwoFactor>, client_headers: ClientHeaders, mu
use crate::db::models::User; use crate::db::models::User;
// Get the user // Get the user
let mut user = match User::find_by_mail(&data.email, &mut conn).await { let Some(mut user) = User::find_by_mail(&data.email, &mut conn).await else {
Some(user) => user, err!("Username or password is incorrect. Try again.")
None => err!("Username or password is incorrect. Try again."),
}; };
// Check password // Check password

@ -309,17 +309,16 @@ async fn delete_webauthn(data: Json<DeleteU2FData>, headers: Headers, mut conn:
err!("Invalid password"); err!("Invalid password");
} }
let mut tf = let Some(mut tf) =
match TwoFactor::find_by_user_and_type(&headers.user.uuid, TwoFactorType::Webauthn as i32, &mut conn).await { TwoFactor::find_by_user_and_type(&headers.user.uuid, TwoFactorType::Webauthn as i32, &mut conn).await
Some(tf) => tf, else {
None => err!("Webauthn data not found!"), err!("Webauthn data not found!")
}; };
let mut data: Vec<WebauthnRegistration> = serde_json::from_str(&tf.data)?; let mut data: Vec<WebauthnRegistration> = serde_json::from_str(&tf.data)?;
let item_pos = match data.iter().position(|r| r.id == id) { let Some(item_pos) = data.iter().position(|r| r.id == id) else {
Some(p) => p, err!("Webauthn entry not found")
None => err!("Webauthn entry not found"),
}; };
let removed_item = data.remove(item_pos); let removed_item = data.remove(item_pos);

@ -157,9 +157,8 @@ async fn _password_login(
// Get the user // Get the user
let username = data.username.as_ref().unwrap().trim(); let username = data.username.as_ref().unwrap().trim();
let mut user = match User::find_by_mail(username, conn).await { let Some(mut user) = User::find_by_mail(username, conn).await else {
Some(user) => user, err!("Username or password is incorrect. Try again", format!("IP: {}. Username: {}.", ip.ip, username))
None => 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. // 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 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 { 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!( err!(
"Auth request not found. Try again.", "Auth request not found. Try again.",
format!("IP: {}. Username: {}.", ip.ip, username), format!("IP: {}. Username: {}.", ip.ip, username),
@ -382,13 +382,11 @@ async fn _user_api_key_login(
) -> JsonResult { ) -> JsonResult {
// Get the user via the client_id // Get the user via the client_id
let client_id = data.client_id.as_ref().unwrap(); let client_id = data.client_id.as_ref().unwrap();
let client_user_uuid = match client_id.strip_prefix("user.") { let Some(client_user_uuid) = client_id.strip_prefix("user.") else {
Some(uuid) => uuid, err!("Malformed client_id", format!("IP: {}.", ip.ip))
None => err!("Malformed client_id", format!("IP: {}.", ip.ip)),
}; };
let user = match User::find_by_uuid(client_user_uuid, conn).await { let Some(user) = User::find_by_uuid(client_user_uuid, conn).await else {
Some(user) => user, err!("Invalid client_id", format!("IP: {}.", ip.ip))
None => err!("Invalid client_id", format!("IP: {}.", ip.ip)),
}; };
// Set the user_uuid here to be passed back used for event logging. // 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 { async fn _organization_api_key_login(data: ConnectData, conn: &mut DbConn, ip: &ClientIp) -> JsonResult {
// Get the org via the client_id // Get the org via the client_id
let client_id = data.client_id.as_ref().unwrap(); let client_id = data.client_id.as_ref().unwrap();
let org_uuid = match client_id.strip_prefix("organization.") { let Some(org_uuid) = client_id.strip_prefix("organization.") else {
Some(uuid) => uuid, err!("Malformed client_id", format!("IP: {}.", ip.ip))
None => err!("Malformed client_id", format!("IP: {}.", ip.ip)),
}; };
let org_api_key = match OrganizationApiKey::find_by_org_uuid(org_uuid, conn).await { let Some(org_api_key) = OrganizationApiKey::find_by_org_uuid(org_uuid, conn).await else {
Some(org_api_key) => org_api_key, err!("Invalid client_id", format!("IP: {}.", ip.ip))
None => err!("Invalid client_id", format!("IP: {}.", ip.ip)),
}; };
// Check API key. // Check API key.
@ -676,9 +672,8 @@ async fn _json_err_twofactor(
} }
Some(tf_type @ TwoFactorType::YubiKey) => { Some(tf_type @ TwoFactorType::YubiKey) => {
let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await { let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await else {
Some(tf) => tf, err!("No YubiKey devices registered")
None => err!("No YubiKey devices registered"),
}; };
let yubikey_metadata: yubikey::YubikeyMetadata = serde_json::from_str(&twofactor.data)?; 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) => { Some(tf_type @ TwoFactorType::Email) => {
let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await { let Some(twofactor) = TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, conn).await else {
Some(tf) => tf, err!("No twofactor email registered")
None => err!("No twofactor email registered"),
}; };
// Send email immediately if email is the only 2FA option // Send email immediately if email is the only 2FA option

@ -155,12 +155,9 @@ pub async fn push_cipher_update(
if cipher.organization_uuid.is_some() { if cipher.organization_uuid.is_some() {
return; return;
}; };
let user_uuid = match &cipher.user_uuid { let Some(user_uuid) = &cipher.user_uuid else {
Some(c) => c, debug!("Cipher has no uuid");
None => { return;
debug!("Cipher has no uuid");
return;
}
}; };
if Device::check_user_has_push_device(user_uuid, conn).await { if Device::check_user_has_push_device(user_uuid, conn).await {

@ -471,9 +471,8 @@ impl<'r> FromRequest<'r> for Headers {
}; };
// Check JWT token is valid and get device and user from it // Check JWT token is valid and get device and user from it
let claims = match decode_login(access_token) { let Ok(claims) = decode_login(access_token) else {
Ok(claims) => claims, err_handler!("Invalid claim")
Err(_) => err_handler!("Invalid claim"),
}; };
let device_uuid = claims.device; let device_uuid = claims.device;
@ -484,23 +483,20 @@ impl<'r> FromRequest<'r> for Headers {
_ => err_handler!("Error getting DB"), _ => err_handler!("Error getting DB"),
}; };
let device = match Device::find_by_uuid_and_user(&device_uuid, &user_uuid, &mut conn).await { let Some(device) = Device::find_by_uuid_and_user(&device_uuid, &user_uuid, &mut conn).await else {
Some(device) => device, err_handler!("Invalid device id")
None => err_handler!("Invalid device id"),
}; };
let user = match User::find_by_uuid(&user_uuid, &mut conn).await { let Some(user) = User::find_by_uuid(&user_uuid, &mut conn).await else {
Some(user) => user, err_handler!("Device has no user associated")
None => err_handler!("Device has no user associated"),
}; };
if user.security_stamp != claims.sstamp { if user.security_stamp != claims.sstamp {
if let Some(stamp_exception) = if let Some(stamp_exception) =
user.stamp_exception.as_deref().and_then(|s| serde_json::from_str::<UserStampException>(s).ok()) user.stamp_exception.as_deref().and_then(|s| serde_json::from_str::<UserStampException>(s).ok())
{ {
let current_route = match request.route().and_then(|r| r.name.as_deref()) { let Some(current_route) = request.route().and_then(|r| r.name.as_deref()) else {
Some(name) => name, err_handler!("Error getting current route for stamp exception")
_ => err_handler!("Error getting current route for stamp exception"),
}; };
// Check if the stamp exception has expired first. // Check if the stamp exception has expired first.

@ -111,6 +111,17 @@ impl AuthRequest {
}} }}
} }
pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option<Self> {
db_run! {conn: {
auth_requests::table
.filter(auth_requests::uuid.eq(uuid))
.filter(auth_requests::user_uuid.eq(user_uuid))
.first::<AuthRequestDb>(conn)
.ok()
.from_db()
}}
}
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
db_run! {conn: { db_run! {conn: {
auth_requests::table auth_requests::table

@ -120,10 +120,11 @@ impl Folder {
Ok(()) Ok(())
} }
pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid_and_user(uuid: &str, user_uuid: &str, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
folders::table folders::table
.filter(folders::uuid.eq(uuid)) .filter(folders::uuid.eq(uuid))
.filter(folders::user_uuid.eq(user_uuid))
.first::<FolderDb>(conn) .first::<FolderDb>(conn)
.ok() .ok()
.from_db() .from_db()

@ -191,10 +191,11 @@ impl Group {
}} }}
} }
pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option<Self> { pub async fn find_by_uuid_and_org(uuid: &str, org_uuid: &str, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: { db_run! { conn: {
groups::table groups::table
.filter(groups::uuid.eq(uuid)) .filter(groups::uuid.eq(uuid))
.filter(groups::organizations_uuid.eq(org_uuid))
.first::<GroupDb>(conn) .first::<GroupDb>(conn)
.ok() .ok()
.from_db() .from_db()

@ -142,16 +142,6 @@ impl OrgPolicy {
}} }}
} }
pub async fn find_by_uuid(uuid: &str, conn: &mut DbConn) -> Option<Self> {
db_run! { conn: {
org_policies::table
.filter(org_policies::uuid.eq(uuid))
.first::<OrgPolicyDb>(conn)
.ok()
.from_db()
}}
}
pub async fn find_by_org(org_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_org(org_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: { db_run! { conn: {
org_policies::table org_policies::table

@ -268,9 +268,8 @@ impl Send {
use data_encoding::BASE64URL_NOPAD; use data_encoding::BASE64URL_NOPAD;
use uuid::Uuid; use uuid::Uuid;
let uuid_vec = match BASE64URL_NOPAD.decode(access_id.as_bytes()) { let Ok(uuid_vec) = BASE64URL_NOPAD.decode(access_id.as_bytes()) else {
Ok(v) => v, return None;
Err(_) => return None,
}; };
let uuid = match Uuid::from_slice(&uuid_vec) { 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<Self> {
db_run! {conn: {
sends::table
.filter(sends::uuid.eq(uuid))
.filter(sends::user_uuid.eq(user_uuid))
.first::<SendDb>(conn)
.ok()
.from_db()
}}
}
pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { pub async fn find_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
db_run! {conn: { db_run! {conn: {
sends::table sends::table

@ -286,9 +286,8 @@ pub async fn send_invite(
} }
} }
let query_string = match query.query() { let Some(query_string) = query.query() else {
None => err!("Failed to build invite URL query parameters"), err!("Failed to build invite URL query parameters")
Some(query) => query,
}; };
let (subject, body_html, body_text) = get_text( 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)); .append_pair("token", &encode_jwt(&claims));
} }
let query_string = match query.query() { let Some(query_string) = query.query() else {
None => err!("Failed to build emergency invite URL query parameters"), err!("Failed to build emergency invite URL query parameters")
Some(query) => query,
}; };
let (subject, body_html, body_text) = get_text( let (subject, body_html, body_text) = get_text(

Loading…
Cancel
Save