From e9aa5a545eda43e2e868f76115a3cc9c13d4cc30 Mon Sep 17 00:00:00 2001 From: Stefan Melmuk <509385+stefan0xC@users.noreply.github.com> Date: Sat, 27 Apr 2024 22:16:05 +0200 Subject: fix emergency access invites (#4337) * fix emergency access invites with no mail when mail is disabled instead of accepting emergency access for all invited users automatically, we only accept if the user already exists on registration of a new account any open emergency access invitations will be accepted, if mail is disabled also prevent invited emergency access contacts to register if emergency access is disabled (this is only relevant for when mail is enabled, if mail is disabled they should have an Invitation entry) * delete emergency access invitations if an invited user is deleted in the /admin panel their emergency access invitation will remain in the database which causes the to_json_grantee_details fn to panic * improve missing emergency access grantees instead of returning an empty emergency access contact the entry should not be added to the list. also the error handling can be improved a bit. --- src/db/models/emergency_access.rs | 56 ++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 9 deletions(-) (limited to 'src/db/models/emergency_access.rs') diff --git a/src/db/models/emergency_access.rs b/src/db/models/emergency_access.rs index c3682920..a0f07e7f 100644 --- a/src/db/models/emergency_access.rs +++ b/src/db/models/emergency_access.rs @@ -81,25 +81,32 @@ impl EmergencyAccess { }) } - pub async fn to_json_grantee_details(&self, conn: &mut DbConn) -> Value { + pub async fn to_json_grantee_details(&self, conn: &mut DbConn) -> Option { let grantee_user = if let Some(grantee_uuid) = self.grantee_uuid.as_deref() { - Some(User::find_by_uuid(grantee_uuid, conn).await.expect("Grantee user not found.")) + User::find_by_uuid(grantee_uuid, conn).await.expect("Grantee user not found.") } else if let Some(email) = self.email.as_deref() { - Some(User::find_by_mail(email, conn).await.expect("Grantee user not found.")) + match User::find_by_mail(email, conn).await { + Some(user) => user, + None => { + // remove outstanding invitations which should not exist + let _ = Self::delete_all_by_grantee_email(email, conn).await; + return None; + } + } } else { - None + return None; }; - json!({ + Some(json!({ "Id": self.uuid, "Status": self.status, "Type": self.atype, "WaitTimeDays": self.wait_time_days, - "GranteeId": grantee_user.as_ref().map_or("", |u| &u.uuid), - "Email": grantee_user.as_ref().map_or("", |u| &u.email), - "Name": grantee_user.as_ref().map_or("", |u| &u.name), + "GranteeId": grantee_user.uuid, + "Email": grantee_user.email, + "Name": grantee_user.name, "Object": "emergencyAccessGranteeDetails", - }) + })) } } @@ -214,6 +221,13 @@ impl EmergencyAccess { Ok(()) } + pub async fn delete_all_by_grantee_email(grantee_email: &str, conn: &mut DbConn) -> EmptyResult { + for ea in Self::find_all_invited_by_grantee_email(grantee_email, conn).await { + ea.delete(conn).await?; + } + Ok(()) + } + pub async fn delete(self, conn: &mut DbConn) -> EmptyResult { User::update_uuid_revision(&self.grantor_uuid, conn).await; @@ -285,6 +299,15 @@ impl EmergencyAccess { }} } + pub async fn find_all_invited_by_grantee_email(grantee_email: &str, conn: &mut DbConn) -> Vec { + db_run! { conn: { + emergency_access::table + .filter(emergency_access::email.eq(grantee_email)) + .filter(emergency_access::status.eq(EmergencyAccessStatus::Invited as i32)) + .load::(conn).expect("Error loading emergency_access").from_db() + }} + } + pub async fn find_all_by_grantor_uuid(grantor_uuid: &str, conn: &mut DbConn) -> Vec { db_run! { conn: { emergency_access::table @@ -292,6 +315,21 @@ impl EmergencyAccess { .load::(conn).expect("Error loading emergency_access").from_db() }} } + + pub async fn accept_invite(&mut self, grantee_uuid: &str, grantee_email: &str, conn: &mut DbConn) -> EmptyResult { + if self.email.is_none() || self.email.as_ref().unwrap() != grantee_email { + err!("User email does not match invite."); + } + + if self.status == EmergencyAccessStatus::Accepted as i32 { + err!("Emergency contact already accepted."); + } + + self.status = EmergencyAccessStatus::Accepted as i32; + self.grantee_uuid = Some(String::from(grantee_uuid)); + self.email = None; + self.save(conn).await + } } // endregion -- cgit v1.2.3