Browse Source

Emergency Access cleanup

This commit contains mostly superficial user-facing cleanup, to be followed up
with more extensive cleanup and fixes in the API implementation.
Jeremy Lin 4 years ago
parent
commit
cee3fd5ba2

+ 10 - 9
.env.template

@@ -61,6 +61,10 @@
 ## To control this on a per-org basis instead, use the "Disable Send" org policy.
 # SENDS_ALLOWED=true
 
+## Controls whether users can enable emergency access to their accounts.
+## This setting applies globally to all users.
+# EMERGENCY_ACCESS_ALLOWED=true
+
 ## Job scheduler settings
 ##
 ## Job schedules use a cron-like syntax (as parsed by https://crates.io/crates/cron),
@@ -78,13 +82,13 @@
 ## Defaults to daily (5 minutes after midnight). Set blank to disable this job.
 # TRASH_PURGE_SCHEDULE="0 5 0 * * *"
 ##
-## Cron schedule of the job that sends expiration reminders to emergency request grantors.
-## Defaults to hourly (10 minutes after the hour). Set blank to disable this job.
-# EMERGENCY_NOTIFICATION_REMINDER_SCHEDULE="0 10 * * * *"
+## Cron schedule of the job that sends expiration reminders to emergency access grantors.
+## Defaults to hourly (5 minutes after the hour). Set blank to disable this job.
+# EMERGENCY_NOTIFICATION_REMINDER_SCHEDULE="0 5 * * * *"
 ##
-## Cron schedule of the job that checks for expired (i.e granted by timeout) emergency requests.
-## Defaults to hourly (15 minutes after the hour). Set blank to disable this job.
-# EMERGENCY_REQUEST_TIMEOUT_SCHEDULE="0 15 * * * *"
+## Cron schedule of the job that grants emergency access requests that have met the required wait time.
+## Defaults to hourly (5 minutes after the hour). Set blank to disable this job.
+# EMERGENCY_REQUEST_TIMEOUT_SCHEDULE="0 5 * * * *"
 
 ## Enable extended logging, which shows timestamps and targets in the logs
 # EXTENDED_LOGGING=true
@@ -320,9 +324,6 @@
 ## If sending the email fails the login attempt will fail!!
 # REQUIRE_DEVICE_EMAIL=false
 
-## Emergency access enable. Enable or disable the emergency access feature for all users
-# EMERGENCY_ACCESS_ALLOWED=false
-
 ## HIBP Api Key
 ## HaveIBeenPwned API Key, request it here: https://haveibeenpwned.com/API/Key
 # HIBP_API_KEY=

+ 3 - 4
src/api/core/accounts.rs

@@ -91,10 +91,9 @@ fn register(data: JsonUpcase<RegisterData>, conn: DbConn) -> EmptyResult {
                 user
             } else if CONFIG.is_signup_allowed(&email) {
                 // check if it's invited by emergency contact
-                if EmergencyAccess::find_invited_by_grantee_email(&data.Email, &conn).is_some() {
-                    user
-                } else {
-                    err!("Account with this email already exists")
+                match EmergencyAccess::find_invited_by_grantee_email(&data.Email, &conn) {
+                    Some(_) => user,
+                    _ => err!("Account with this email already exists"),
                 }
             } else {
                 err!("Registration not allowed or user already exists")

+ 4 - 4
src/api/core/emergency_access.rs

@@ -464,7 +464,7 @@ fn initiate_emergency_access(emer_id: String, headers: Headers, conn: DbConn) ->
         mail::send_emergency_access_recovery_initiated(
             &grantor_user.email,
             &initiating_user.name,
-            emergency_access.get_atype_as_str(),
+            emergency_access.get_type_as_str(),
             &emergency_access.wait_time_days.clone().to_string(),
         )?;
     }
@@ -743,7 +743,7 @@ pub fn emergency_request_timeout_job(pool: DbPool) {
                     mail::send_emergency_access_recovery_timed_out(
                         &grantor_user.email,
                         &grantee_user.name.clone(),
-                        emer.get_atype_as_str(),
+                        emer.get_type_as_str(),
                     )
                     .expect("Error on sending email");
 
@@ -792,8 +792,8 @@ pub fn emergency_notification_reminder_job(pool: DbPool) {
                     mail::send_emergency_access_recovery_reminder(
                         &grantor_user.email,
                         &grantee_user.name.clone(),
-                        emer.get_atype_as_str(),
-                        &emer.wait_time_days.to_string(),
+                        emer.get_type_as_str(),
+                        &emer.wait_time_days.to_string(), // TODO(jjlin): This should be the number of days left.
                     )
                     .expect("Error on sending email");
                 }

+ 5 - 5
src/config.rs

@@ -333,12 +333,12 @@ make_config! {
         /// Trash purge schedule |> Cron schedule of the job that checks for trashed items to delete permanently.
         /// Defaults to daily. Set blank to disable this job.
         trash_purge_schedule:   String, false,  def,    "0 5 0 * * *".to_string();
-        /// Emergency notification reminder schedule |> Cron schedule of the job that sends expiration reminders to emergency request grantors.
+        /// Emergency notification reminder schedule |> Cron schedule of the job that sends expiration reminders to emergency access grantors.
         /// Defaults to hourly. Set blank to disable this job.
-        emergency_notification_reminder_schedule:   String, false,  def,    "0 10 * * * *".to_string();
-        /// Emergency request timeout schedule |> Cron schedule of the job that checks for expired (i.e granted by timeout) emergency requests.
+        emergency_notification_reminder_schedule:   String, false,  def,    "0 5 * * * *".to_string();
+        /// Emergency request timeout schedule |> Cron schedule of the job that grants emergency access requests that have met the required wait time.
         /// Defaults to hourly. Set blank to disable this job.
-        emergency_request_timeout_schedule:   String, false,  def,    "0 15 * * * *".to_string();
+        emergency_request_timeout_schedule:   String, false,  def,    "0 5 * * * *".to_string();
     },
 
     /// General settings
@@ -391,7 +391,7 @@ make_config! {
         org_creation_users:     String, true,   def,    "".to_string();
         /// Allow invitations |> Controls whether users can be invited by organization admins, even when signups are otherwise disabled
         invitations_allowed:    bool,   true,   def,    true;
-        /// Allow emergency access |> Controls whether users can enable emergency access to their accounts
+        /// Allow emergency access |> Controls whether users can enable emergency access to their accounts. This setting applies globally to all users.
         emergency_access_allowed:    bool,   true,   def,    true;
         /// Password iterations |> Number of server-side passwords hashing iterations.
         /// The changes only apply when a user changes their password. Not recommended to lower the value

+ 37 - 45
src/db/models/emergency_access.rs

@@ -47,7 +47,7 @@ impl EmergencyAccess {
         }
     }
 
-    pub fn get_atype_as_str(&self) -> &'static str {
+    pub fn get_type_as_str(&self) -> &'static str {
         if self.atype == EmergencyAccessType::View as i32 {
             "View"
         } else {
@@ -55,6 +55,14 @@ impl EmergencyAccess {
         }
     }
 
+    pub fn has_type(&self, access_type: EmergencyAccessType) -> bool {
+        self.atype == access_type as i32
+    }
+
+    pub fn has_status(&self, status: EmergencyAccessStatus) -> bool {
+        self.status == status as i32
+    }
+
     pub fn to_json(&self) -> Value {
         json!({
             "Id": self.uuid,
@@ -66,55 +74,40 @@ impl EmergencyAccess {
     }
 
     pub fn to_json_grantor_details(&self, conn: &DbConn) -> Value {
-        // find grantor
-        let grantor_user = User::find_by_uuid(&self.grantor_uuid, conn).unwrap();
+        let grantor_user = User::find_by_uuid(&self.grantor_uuid, conn).expect("Grantor user not found.");
+
         json!({
-             "Id": self.uuid,
+            "Id": self.uuid,
             "Status": self.status,
             "Type": self.atype,
             "WaitTimeDays": self.wait_time_days,
             "GrantorId": grantor_user.uuid,
             "Email": grantor_user.email,
             "Name": grantor_user.name,
-            "Object": "emergencyAccessGrantorDetails",})
+            "Object": "emergencyAccessGrantorDetails",
+        })
     }
 
+    #[allow(clippy::manual_map)]
     pub fn to_json_grantee_details(&self, conn: &DbConn) -> Value {
-        if self.grantee_uuid.is_some() {
-            let grantee_user =
-                User::find_by_uuid(&self.grantee_uuid.clone().unwrap(), conn).expect("Grantee user not found.");
-
-            json!({
-                "Id": self.uuid,
-                "Status": self.status,
-                "Type": self.atype,
-                "WaitTimeDays": self.wait_time_days,
-                "GranteeId": grantee_user.uuid,
-                "Email": grantee_user.email,
-                "Name": grantee_user.name,
-                "Object": "emergencyAccessGranteeDetails",})
-        } else if self.email.is_some() {
-            let grantee_user = User::find_by_mail(&self.email.clone().unwrap(), conn).expect("Grantee user not found.");
-            json!({
-                    "Id": self.uuid,
-                    "Status": self.status,
-                    "Type": self.atype,
-                    "WaitTimeDays": self.wait_time_days,
-                    "GranteeId": grantee_user.uuid,
-                    "Email": grantee_user.email,
-                    "Name": grantee_user.name,
-                    "Object": "emergencyAccessGranteeDetails",})
+        let grantee_user = if let Some(grantee_uuid) = self.grantee_uuid.as_deref() {
+            Some(User::find_by_uuid(grantee_uuid, conn).expect("Grantee user not found."))
+        } else if let Some(email) = self.email.as_deref() {
+            Some(User::find_by_mail(email, conn).expect("Grantee user not found."))
         } else {
-            json!({
-                "Id": self.uuid,
-                "Status": self.status,
-                "Type": self.atype,
-                "WaitTimeDays": self.wait_time_days,
-                "GranteeId": "",
-                "Email": "",
-                "Name": "",
-                "Object": "emergencyAccessGranteeDetails",})
-        }
+            None
+        };
+
+        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),
+            "Object": "emergencyAccessGranteeDetails",
+        })
     }
 }
 
@@ -198,11 +191,11 @@ impl EmergencyAccess {
     }
 
     pub fn delete_all_by_user(user_uuid: &str, conn: &DbConn) -> EmptyResult {
-        for user_org in Self::find_all_by_grantor_uuid(user_uuid, conn) {
-            user_org.delete(conn)?;
+        for ea in Self::find_all_by_grantor_uuid(user_uuid, conn) {
+            ea.delete(conn)?;
         }
-        for user_org in Self::find_all_by_grantee_uuid(user_uuid, conn) {
-            user_org.delete(conn)?;
+        for ea in Self::find_all_by_grantee_uuid(user_uuid, conn) {
+            ea.delete(conn)?;
         }
         Ok(())
     }
@@ -213,7 +206,7 @@ impl EmergencyAccess {
         db_run! { conn: {
             diesel::delete(emergency_access::table.filter(emergency_access::uuid.eq(self.uuid)))
                 .execute(conn)
-                .map_res("Error removing user from organization")
+                .map_res("Error removing user from emergency access")
         }}
     }
 
@@ -246,7 +239,6 @@ impl EmergencyAccess {
             emergency_access::table
                 .filter(emergency_access::status.eq(EmergencyAccessStatus::RecoveryInitiated as i32))
                 .load::<EmergencyAccessDb>(conn).expect("Error loading emergency_access").from_db()
-
         }}
     }
 

+ 2 - 2
src/mail.rs

@@ -329,7 +329,7 @@ pub fn send_emergency_access_recovery_reminder(
     address: &str,
     grantee_name: &str,
     atype: &str,
-    wait_time_days: &str,
+    days_left: &str,
 ) -> EmptyResult {
     let (subject, body_html, body_text) = get_text(
         "email/emergency_access_recovery_reminder",
@@ -337,7 +337,7 @@ pub fn send_emergency_access_recovery_reminder(
             "url": CONFIG.domain(),
             "grantee_name": grantee_name,
             "atype": atype,
-            "wait_time_days": wait_time_days,
+            "days_left": days_left,
         }),
     )?;
 

+ 9 - 0
src/main.rs

@@ -345,12 +345,17 @@ fn schedule_jobs(pool: db::DbPool) {
                 }));
             }
 
+            // Grant emergency access requests that have met the required wait time.
+            // This job should run before the emergency access reminders job to avoid
+            // sending reminders for requests that are about to be granted anyway.
             if !CONFIG.emergency_request_timeout_schedule().is_empty() {
                 sched.add(Job::new(CONFIG.emergency_request_timeout_schedule().parse().unwrap(), || {
                     api::emergency_request_timeout_job(pool.clone());
                 }));
             }
 
+            // Send reminders to emergency access grantors that there are pending
+            // emergency access requests.
             if !CONFIG.emergency_notification_reminder_schedule().is_empty() {
                 sched.add(Job::new(CONFIG.emergency_notification_reminder_schedule().parse().unwrap(), || {
                     api::emergency_notification_reminder_job(pool.clone());
@@ -362,6 +367,10 @@ fn schedule_jobs(pool: db::DbPool) {
             // interval of 30 seconds should be sufficient. Users who want to
             // schedule jobs to run more frequently for some reason can reduce
             // the poll interval accordingly.
+            //
+            // Note that the scheduler checks jobs in the order in which they
+            // were added, so if two jobs are both eligible to run at a given
+            // tick, the one that was added earlier will run first.
             loop {
                 sched.tick();
                 thread::sleep(Duration::from_millis(CONFIG.job_poll_interval_ms()));

+ 2 - 2
src/static/templates/email/emergency_access_invite_accepted.hbs

@@ -1,8 +1,8 @@
-Emergency contact {{{grantee_email}}} accepted
+Emergency access contact {{{grantee_email}}} accepted
 <!---------------->
 This email is to notify you that {{grantee_email}} has accepted your invitation to become an emergency access contact.
 
-To confirm this user, Log into {{url}} the Bitwarden web vault, go to settings and confirm the user.
+To confirm this user, log into the web vault ({{url}}), go to settings and confirm the user.
 
 If you do not wish to confirm this user, you can also remove them on the same page.
 {{> email/email_footer_text }}

+ 3 - 3
src/static/templates/email/emergency_access_invite_accepted.html.hbs

@@ -1,4 +1,4 @@
-Emergency contact {{{grantee_email}}} accepted
+Emergency access contact {{{grantee_email}}} accepted
 <!---------------->
 {{> email/email_header }}
 <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
@@ -9,7 +9,7 @@ Emergency contact {{{grantee_email}}} accepted
     </tr>
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
         <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
-            To confirm this user, <a href="{{url}}/">log into</a> the vaultwarden web vault, go to settings and confirm the user.
+            To confirm this user, log into the <a href="{{url}}/">web vault</a>, go to settings and confirm the user.
         </td>
     </tr>
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
@@ -18,4 +18,4 @@ Emergency contact {{{grantee_email}}} accepted
         </td>
     </tr>
 </table>
-{{> email/email_footer }}
+{{> email/email_footer }}

+ 3 - 3
src/static/templates/email/emergency_access_invite_confirmed.hbs

@@ -1,6 +1,6 @@
-Emergency contact for {{{grantor_name}}} confirmed
+Emergency access contact for {{{grantor_name}}} confirmed
 <!---------------->
-This email is to notify you that you have been confirmed as an emergency access contact for *{{grantor_name}}* was confirmed.
+This email is to notify you that you have been confirmed as an emergency access contact for *{{grantor_name}}*.
 
-You can now initiate emergency access requests from the web vault. Log in {{url}}.
+You can now initiate emergency access requests from the web vault ({{url}}).
 {{> email/email_footer_text }}

+ 4 - 5
src/static/templates/email/emergency_access_invite_confirmed.html.hbs

@@ -1,17 +1,16 @@
-Emergency contact for {{{grantor_name}}} confirmed
+Emergency access contact for {{{grantor_name}}} confirmed
 <!---------------->
 {{> email/email_header }}
  <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
        <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
-           This email is to notify you that you have been confirmed as an emergency access contact for <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantor_name}}</b> was confirmed.
+           This email is to notify you that you have been confirmed as an emergency access contact for <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantor_name}}</b>.
        </td>
     </tr>
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
        <td class="content-block last" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none;" valign="top">
-           You can now initiate emergency access requests from the web vault. <br>
-          <a href="{{url}}/">Log in</a>
+           You can now initiate emergency access requests from the <a href="{{url}}/">web vault</a>.
        </td>
     </tr>
  </table>
-{{> email/email_footer }}
+{{> email/email_footer }}

+ 2 - 2
src/static/templates/email/emergency_access_recovery_approved.hbs

@@ -1,4 +1,4 @@
-Emergency contact request for {{{grantor_name}}} approved
+Emergency access request for {{{grantor_name}}} approved
 <!---------------->
-{{grantor_name}} has approved your emergency request. You may now login {{url}} on the web vault and access their account.
+{{grantor_name}} has approved your emergency access request. You may now login on the web vault ({{url}}) and access their account.
 {{> email/email_footer_text }}

+ 3 - 3
src/static/templates/email/emergency_access_recovery_approved.html.hbs

@@ -1,11 +1,11 @@
-Emergency contact for {{{grantor_name}}} approved
+Emergency access request for {{{grantor_name}}} approved
 <!---------------->
 {{> email/email_header }}
  <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
        <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
-           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantor_name}}</b> has approved your emergency request. You may now <a href="{{url}}/">login</a> on the web vault and access their account.
+           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantor_name}}</b> has approved your emergency access request. You may now login on the <a href="{{url}}/">web vault</a> and access their account.
        </td>
     </tr>
  </table>
-{{> email/email_footer }}
+{{> email/email_footer }}

+ 1 - 1
src/static/templates/email/emergency_access_recovery_initiated.hbs

@@ -1,6 +1,6 @@
 Emergency access request by {{{grantee_name}}} initiated
 <!---------------->
-{{grantee_name}} has initiated an emergency request to *{{atype}}* your account. You may login on the web vault and manually approve or reject this request.
+{{grantee_name}} has initiated an emergency access request to {{atype}} your account. You may login on the web vault ({{url}}) and manually approve or reject this request.
 
 If you do nothing, the request will automatically be approved after {{wait_time_days}} day(s).
 {{> email/email_footer_text }}

+ 2 - 2
src/static/templates/email/emergency_access_recovery_initiated.html.hbs

@@ -4,7 +4,7 @@ Emergency access request by {{{grantee_name}}} initiated
  <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
        <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
-           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantee_name}}</b> has initiated an emergency request to <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{atype}}</b> your account. You may login on the web vault and manually approve or reject this request.
+           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantee_name}}</b> has initiated an emergency access request to <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{atype}}</b> your account. You may login on the <a href="{{url}}/">web vault</a> and manually approve or reject this request.
        </td>
     </tr>
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
@@ -13,4 +13,4 @@ Emergency access request by {{{grantee_name}}} initiated
        </td>
     </tr>
  </table>
-{{> email/email_footer }}
+{{> email/email_footer }}

+ 1 - 1
src/static/templates/email/emergency_access_recovery_rejected.hbs

@@ -1,4 +1,4 @@
 Emergency access request to {{{grantor_name}}} rejected
 <!---------------->
-{{grantor_name}} has rejected your emergency request.
+{{grantor_name}} has rejected your emergency access request.
 {{> email/email_footer_text }}

+ 2 - 2
src/static/templates/email/emergency_access_recovery_rejected.html.hbs

@@ -4,8 +4,8 @@ Emergency access request to {{{grantor_name}}} rejected
  <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
        <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
-           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantor_name}}</b>  has rejected your emergency request.
+           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantor_name}}</b>  has rejected your emergency access request.
        </td>
     </tr>
  </table>
-{{> email/email_footer }}
+{{> email/email_footer }}

+ 2 - 2
src/static/templates/email/emergency_access_recovery_reminder.hbs

@@ -1,6 +1,6 @@
 Emergency access request by {{{grantee_name}}} is pending
 <!---------------->
-{{grantee_name}} has a pending emergency request to *{{atype}}* your account. You may login on the web vault and manually approve or reject this request.
+{{grantee_name}} has a pending emergency access request to {{atype}} your account. You may login on the web vault ({{url}}) and manually approve or reject this request.
 
-If you do nothing, the request will automatically be approved after {{wait_time_days}} day(s).
+If you do nothing, the request will automatically be approved after {{days_left}} day(s).
 {{> email/email_footer_text }}

+ 3 - 3
src/static/templates/email/emergency_access_recovery_reminder.html.hbs

@@ -4,13 +4,13 @@ Emergency access request by {{{grantee_name}}} is pending
  <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
        <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
-           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantee_name}}</b> has a pending emergency request to <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{atype}}</b> your account. You may login on the web vault and manually approve or reject this request.
+           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantee_name}}</b> has a pending emergency access request to <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{atype}}</b> your account. You may login on the <a href="{{url}}/">web vault</a> and manually approve or reject this request.
        </td>
     </tr>
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
        <td class="content-block last" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0; -webkit-text-size-adjust: none;" valign="top">
-           If you do nothing, the request will automatically be approved after <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{wait_time_days}}</b> day(s).
+           If you do nothing, the request will automatically be approved after <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{days_left}}</b> day(s).
        </td>
     </tr>
  </table>
-{{> email/email_footer }}
+{{> email/email_footer }}

+ 1 - 1
src/static/templates/email/emergency_access_recovery_timed_out.hbs

@@ -1,4 +1,4 @@
 Emergency access request by {{{grantee_name}}} granted
 <!---------------->
-{{grantee_name}} has been granted emergency request to *{{atype}}* your account. You may login on the web vault and manually revoke this request.
+{{grantee_name}} has been granted emergency access to {{atype}} your account. You may login on the web vault ({{url}}) and manually revoke this request.
 {{> email/email_footer_text }}

+ 2 - 2
src/static/templates/email/emergency_access_recovery_timed_out.html.hbs

@@ -4,8 +4,8 @@ Emergency access request by {{{grantee_name}}} granted
  <table width="100%" cellpadding="0" cellspacing="0" style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
     <tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
        <td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
-           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantee_name}}</b> has been granted emergency request to <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{atype}}</b> your account. You may login on the web vault and manually revoke this request.
+           <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{grantee_name}}</b> has been granted emergency access to <b style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">{{atype}}</b> your account. You may login on the <a href="{{url}}/">web vault</a> and manually revoke this request.
        </td>
     </tr>
  </table>
-{{> email/email_footer }}
+{{> email/email_footer }}