aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/api/core/accounts.rs12
-rw-r--r--src/api/core/emergency_access.rs69
-rw-r--r--src/db/models/emergency_access.rs56
-rw-r--r--src/db/models/user.rs1
4 files changed, 78 insertions, 60 deletions
diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs
index b2afe905..5b947b85 100644
--- a/src/api/core/accounts.rs
+++ b/src/api/core/accounts.rs
@@ -166,7 +166,8 @@ pub async fn _register(data: JsonUpcase<RegisterData>, mut conn: DbConn) -> Json
}
user
} else if CONFIG.is_signup_allowed(&email)
- || EmergencyAccess::find_invited_by_grantee_email(&email, &mut conn).await.is_some()
+ || (CONFIG.emergency_access_allowed()
+ && EmergencyAccess::find_invited_by_grantee_email(&email, &mut conn).await.is_some())
{
user
} else {
@@ -217,7 +218,6 @@ pub async fn _register(data: JsonUpcase<RegisterData>, mut conn: DbConn) -> Json
if let Err(e) = mail::send_welcome_must_verify(&user.email, &user.uuid).await {
error!("Error sending welcome email: {:#?}", e);
}
-
user.last_verifying_at = Some(user.created_at);
} else if let Err(e) = mail::send_welcome(&user.email).await {
error!("Error sending welcome email: {:#?}", e);
@@ -229,6 +229,14 @@ pub async fn _register(data: JsonUpcase<RegisterData>, mut conn: DbConn) -> Json
}
user.save(&mut conn).await?;
+
+ // accept any open emergency access invitations
+ if !CONFIG.mail_enabled() && CONFIG.emergency_access_allowed() {
+ for mut emergency_invite in EmergencyAccess::find_all_invited_by_grantee_email(&user.email, &mut conn).await {
+ let _ = emergency_invite.accept_invite(&user.uuid, &user.email, &mut conn).await;
+ }
+ }
+
Ok(Json(json!({
"Object": "register",
"CaptchaBypassToken": "",
diff --git a/src/api/core/emergency_access.rs b/src/api/core/emergency_access.rs
index 5f64cde0..5d522c61 100644
--- a/src/api/core/emergency_access.rs
+++ b/src/api/core/emergency_access.rs
@@ -61,7 +61,9 @@ async fn get_contacts(headers: Headers, mut conn: DbConn) -> Json<Value> {
let emergency_access_list = EmergencyAccess::find_all_by_grantor_uuid(&headers.user.uuid, &mut conn).await;
let mut emergency_access_list_json = Vec::with_capacity(emergency_access_list.len());
for ea in emergency_access_list {
- emergency_access_list_json.push(ea.to_json_grantee_details(&mut conn).await);
+ if let Some(grantee) = ea.to_json_grantee_details(&mut conn).await {
+ emergency_access_list_json.push(grantee)
+ }
}
Json(json!({
@@ -95,7 +97,9 @@ async fn get_emergency_access(emer_id: &str, mut conn: DbConn) -> JsonResult {
check_emergency_access_enabled()?;
match EmergencyAccess::find_by_uuid(emer_id, &mut conn).await {
- Some(emergency_access) => Ok(Json(emergency_access.to_json_grantee_details(&mut conn).await)),
+ Some(emergency_access) => Ok(Json(
+ emergency_access.to_json_grantee_details(&mut conn).await.expect("Grantee user should exist but does not!"),
+ )),
None => err!("Emergency access not valid."),
}
}
@@ -209,7 +213,7 @@ async fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Heade
err!("You can not set yourself as an emergency contact.")
}
- let grantee_user = match User::find_by_mail(&email, &mut conn).await {
+ let (grantee_user, new_user) = match User::find_by_mail(&email, &mut conn).await {
None => {
if !CONFIG.invitations_allowed() {
err!(format!("Grantee user does not exist: {}", &email))
@@ -226,9 +230,10 @@ async fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Heade
let mut user = User::new(email.clone());
user.save(&mut conn).await?;
- user
+ (user, true)
}
- Some(user) => user,
+ Some(user) if user.password_hash.is_empty() => (user, true),
+ Some(user) => (user, false),
};
if EmergencyAccess::find_by_grantor_uuid_and_grantee_uuid_or_email(
@@ -256,15 +261,9 @@ async fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Heade
&grantor_user.email,
)
.await?;
- } else {
- // Automatically mark user as accepted if no email invites
- match User::find_by_mail(&email, &mut conn).await {
- Some(user) => match accept_invite_process(&user.uuid, &mut new_emergency_access, &email, &mut conn).await {
- Ok(v) => v,
- Err(e) => err!(e.to_string()),
- },
- None => err!("Grantee user not found."),
- }
+ } else if !new_user {
+ // if mail is not enabled immediately accept the invitation for existing users
+ new_emergency_access.accept_invite(&grantee_user.uuid, &email, &mut conn).await?;
}
Ok(())
@@ -308,17 +307,12 @@ async fn resend_invite(emer_id: &str, headers: Headers, mut conn: DbConn) -> Emp
&grantor_user.email,
)
.await?;
- } else {
- if Invitation::find_by_mail(&email, &mut conn).await.is_none() {
- let invitation = Invitation::new(&email);
- invitation.save(&mut conn).await?;
- }
-
- // Automatically mark user as accepted if no email invites
- match accept_invite_process(&grantee_user.uuid, &mut emergency_access, &email, &mut conn).await {
- Ok(v) => v,
- Err(e) => err!(e.to_string()),
- }
+ } else if !grantee_user.password_hash.is_empty() {
+ // accept the invitation for existing user
+ emergency_access.accept_invite(&grantee_user.uuid, &email, &mut conn).await?;
+ } else if CONFIG.invitations_allowed() && Invitation::find_by_mail(&email, &mut conn).await.is_none() {
+ let invitation = Invitation::new(&email);
+ invitation.save(&mut conn).await?;
}
Ok(())
@@ -367,10 +361,7 @@ async fn accept_invite(emer_id: &str, data: JsonUpcase<AcceptData>, headers: Hea
&& grantor_user.name == claims.grantor_name
&& grantor_user.email == claims.grantor_email
{
- match accept_invite_process(&grantee_user.uuid, &mut emergency_access, &grantee_user.email, &mut conn).await {
- Ok(v) => v,
- Err(e) => err!(e.to_string()),
- }
+ emergency_access.accept_invite(&grantee_user.uuid, &grantee_user.email, &mut conn).await?;
if CONFIG.mail_enabled() {
mail::send_emergency_access_invite_accepted(&grantor_user.email, &grantee_user.email).await?;
@@ -382,26 +373,6 @@ async fn accept_invite(emer_id: &str, data: JsonUpcase<AcceptData>, headers: Hea
}
}
-async fn accept_invite_process(
- grantee_uuid: &str,
- emergency_access: &mut EmergencyAccess,
- grantee_email: &str,
- conn: &mut DbConn,
-) -> EmptyResult {
- if emergency_access.email.is_none() || emergency_access.email.as_ref().unwrap() != grantee_email {
- err!("User email does not match invite.");
- }
-
- if emergency_access.status == EmergencyAccessStatus::Accepted as i32 {
- err!("Emergency contact already accepted.");
- }
-
- emergency_access.status = EmergencyAccessStatus::Accepted as i32;
- emergency_access.grantee_uuid = Some(String::from(grantee_uuid));
- emergency_access.email = None;
- emergency_access.save(conn).await
-}
-
#[derive(Deserialize)]
#[allow(non_snake_case)]
struct ConfirmData {
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<Value> {
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<Self> {
+ db_run! { conn: {
+ emergency_access::table
+ .filter(emergency_access::email.eq(grantee_email))
+ .filter(emergency_access::status.eq(EmergencyAccessStatus::Invited as i32))
+ .load::<EmergencyAccessDb>(conn).expect("Error loading emergency_access").from_db()
+ }}
+ }
+
pub async fn find_all_by_grantor_uuid(grantor_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
db_run! { conn: {
emergency_access::table
@@ -292,6 +315,21 @@ impl EmergencyAccess {
.load::<EmergencyAccessDb>(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
diff --git a/src/db/models/user.rs b/src/db/models/user.rs
index feb09438..bf7dad32 100644
--- a/src/db/models/user.rs
+++ b/src/db/models/user.rs
@@ -311,6 +311,7 @@ impl User {
Send::delete_all_by_user(&self.uuid, conn).await?;
EmergencyAccess::delete_all_by_user(&self.uuid, conn).await?;
+ EmergencyAccess::delete_all_by_grantee_email(&self.email, conn).await?;
UserOrganization::delete_all_by_user(&self.uuid, conn).await?;
Cipher::delete_all_by_user(&self.uuid, conn).await?;
Favorite::delete_all_by_user(&self.uuid, conn).await?;