Skip to content

Commit

Permalink
Actually use Device Type for mails
Browse files Browse the repository at this point in the history
- match Bitwarden behaviour
- add a different segment in mails for Device Name
  • Loading branch information
dfunkt committed Sep 7, 2024
1 parent 66baa5e commit e123c93
Show file tree
Hide file tree
Showing 17 changed files with 80 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` DROP COLUMN `device_type`;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` ADD COLUMN `device_type` INTEGER NOT NULL;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` DROP COLUMN `device_type`;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` ADD COLUMN `device_type` INTEGER NOT NULL;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` DROP COLUMN `device_type`;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` ADD COLUMN `device_type` INTEGER NOT NULL;
10 changes: 8 additions & 2 deletions src/api/core/two_factor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,14 @@ pub async fn send_incomplete_2fa_notifications(pool: DbPool) {
"User {} did not complete a 2FA login within the configured time limit. IP: {}",
user.email, login.ip_address
);
match mail::send_incomplete_2fa_login(&user.email, &login.ip_address, &login.login_time, &login.device_name)
.await
match mail::send_incomplete_2fa_login(
&user.email,
&login.ip_address,
&login.login_time,
&login.device_name,
&DeviceType::from_i32(login.device_type).to_string(),
)
.await
{
Ok(_) => {
if let Err(e) = login.delete(&mut conn).await {
Expand Down
22 changes: 19 additions & 3 deletions src/api/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,15 @@ async fn _password_login(
let twofactor_token = twofactor_auth(&user, &data, &mut device, ip, conn).await?;

if CONFIG.mail_enabled() && new_device {
if let Err(e) = mail::send_new_device_logged_in(&user.email, &ip.ip.to_string(), &now, &device.name).await {
if let Err(e) = mail::send_new_device_logged_in(
&user.email,
&ip.ip.to_string(),
&now,
&device.name,
&DeviceType::from_i32(device.atype).to_string(),
)
.await
{
error!("Error sending new device email: {:#?}", e);

if CONFIG.require_device_email() {
Expand Down Expand Up @@ -421,7 +429,15 @@ async fn _user_api_key_login(

if CONFIG.mail_enabled() && new_device {
let now = Utc::now().naive_utc();
if let Err(e) = mail::send_new_device_logged_in(&user.email, &ip.ip.to_string(), &now, &device.name).await {
if let Err(e) = mail::send_new_device_logged_in(
&user.email,
&ip.ip.to_string(),
&now,
&device.name,
&DeviceType::from_i32(device.atype).to_string(),
)
.await
{
error!("Error sending new device email: {:#?}", e);

if CONFIG.require_device_email() {
Expand Down Expand Up @@ -535,7 +551,7 @@ async fn twofactor_auth(
return Ok(None);
}

TwoFactorIncomplete::mark_incomplete(&user.uuid, &device.uuid, &device.name, ip, conn).await?;
TwoFactorIncomplete::mark_incomplete(&user.uuid, &device.uuid, &device.name, device.atype, ip, conn).await?;

let twofactor_ids: Vec<_> = twofactors.iter().map(|tf| tf.atype).collect();
let selected_id = data.two_factor_provider.unwrap_or(twofactor_ids[0]); // If we aren't given a two factor provider, assume the first one
Expand Down
3 changes: 3 additions & 0 deletions src/db/models/two_factor_incomplete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ db_object! {
// must complete 2FA login before being added into the devices table.
pub device_uuid: String,
pub device_name: String,
pub device_type: i32,
pub login_time: NaiveDateTime,
pub ip_address: String,
}
Expand All @@ -23,6 +24,7 @@ impl TwoFactorIncomplete {
user_uuid: &str,
device_uuid: &str,
device_name: &str,
device_type: i32,
ip: &ClientIp,
conn: &mut DbConn,
) -> EmptyResult {
Expand All @@ -44,6 +46,7 @@ impl TwoFactorIncomplete {
twofactor_incomplete::user_uuid.eq(user_uuid),
twofactor_incomplete::device_uuid.eq(device_uuid),
twofactor_incomplete::device_name.eq(device_name),
twofactor_incomplete::device_type.eq(device_type),
twofactor_incomplete::login_time.eq(Utc::now().naive_utc()),
twofactor_incomplete::ip_address.eq(ip.ip.to_string()),
))
Expand Down
1 change: 1 addition & 0 deletions src/db/schemas/mysql/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ table! {
user_uuid -> Text,
device_uuid -> Text,
device_name -> Text,
device_type -> Integer,
login_time -> Timestamp,
ip_address -> Text,
}
Expand Down
1 change: 1 addition & 0 deletions src/db/schemas/postgresql/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ table! {
user_uuid -> Text,
device_uuid -> Text,
device_name -> Text,
device_type -> Integer,
login_time -> Timestamp,
ip_address -> Text,
}
Expand Down
1 change: 1 addition & 0 deletions src/db/schemas/sqlite/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ table! {
user_uuid -> Text,
device_uuid -> Text,
device_name -> Text,
device_type -> Integer,
login_time -> Timestamp,
ip_address -> Text,
}
Expand Down
26 changes: 20 additions & 6 deletions src/mail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,9 +446,15 @@ pub async fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult
send_email(address, &subject, body_html, body_text).await
}

pub async fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTime, device: &str) -> EmptyResult {
pub async fn send_new_device_logged_in(
address: &str,
ip: &str,
dt: &NaiveDateTime,
device_name: &str,
device_type: &str,
) -> EmptyResult {
use crate::util::upcase_first;
let device = upcase_first(device);
let device_name = upcase_first(device_name);

let fmt = "%A, %B %_d, %Y at %r %Z";
let (subject, body_html, body_text) = get_text(
Expand All @@ -457,17 +463,24 @@ pub async fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTi
"url": CONFIG.domain(),
"img_src": CONFIG._smtp_img_src(),
"ip": ip,
"device": device,
"device_name": device_name,
"device_type": device_type,
"datetime": crate::util::format_naive_datetime_local(dt, fmt),
}),
)?;

send_email(address, &subject, body_html, body_text).await
}

pub async fn send_incomplete_2fa_login(address: &str, ip: &str, dt: &NaiveDateTime, device: &str) -> EmptyResult {
pub async fn send_incomplete_2fa_login(
address: &str,
ip: &str,
dt: &NaiveDateTime,
device_name: &str,
device_type: &str,
) -> EmptyResult {
use crate::util::upcase_first;
let device = upcase_first(device);
let device_name = upcase_first(device_name);

let fmt = "%A, %B %_d, %Y at %r %Z";
let (subject, body_html, body_text) = get_text(
Expand All @@ -476,7 +489,8 @@ pub async fn send_incomplete_2fa_login(address: &str, ip: &str, dt: &NaiveDateTi
"url": CONFIG.domain(),
"img_src": CONFIG._smtp_img_src(),
"ip": ip,
"device": device,
"device_name": device_name,
"device_type": device_type,
"datetime": crate::util::format_naive_datetime_local(dt, fmt),
"time_limit": CONFIG.incomplete_2fa_time_limit(),
}),
Expand Down
5 changes: 3 additions & 2 deletions src/static/templates/email/incomplete_2fa_login.hbs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
Incomplete Two-Step Login From {{{device}}}
Incomplete Two-Step Login From {{{device_name}}}
<!---------------->
Someone attempted to log into your account with the correct master password, but did not provide the correct token or action required to complete the two-step login process within {{time_limit}} minutes of the initial login attempt.

* Date: {{datetime}}
* IP Address: {{ip}}
* Device Type: {{device}}
* Device Name: {{device_name}}
* Device Type: {{device_type}}

If this was not you or someone you authorized, then you should change your master password as soon as possible, as it is likely to be compromised.
{{> email/email_footer_text }}
9 changes: 7 additions & 2 deletions src/static/templates/email/incomplete_2fa_login.html.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Incomplete Two-Step Login From {{{device}}}
Incomplete Two-Step Login From {{{device_name}}}
<!---------------->
{{> 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;">
Expand All @@ -19,7 +19,12 @@ Incomplete Two-Step Login From {{{device}}}
</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">
<b>Device Type:</b> {{device}}
<b>Device Name:</b> {{device_name}}
</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" 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>Device Type:</b> {{device_type}}
</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;">
Expand Down
7 changes: 4 additions & 3 deletions src/static/templates/email/new_device_logged_in.hbs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
New Device Logged In From {{{device}}}
New Device Logged In From {{{device_name}}}
<!---------------->
Your account was just logged into from a new device.

* Date: {{datetime}}
* IP Address: {{ip}}
* Device Type: {{device}}
* Device Name: {{device_name}}
* Device Type: {{device_type}}

You can deauthorize all devices that have access to your account from the web vault ( {{url}} ) under Settings > My Account > Deauthorize Sessions.
{{> email/email_footer_text }}
{{> email/email_footer_text }}
9 changes: 7 additions & 2 deletions src/static/templates/email/new_device_logged_in.html.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
New Device Logged In From {{{device}}}
New Device Logged In From {{{device_name}}}
<!---------------->
{{> 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;">
Expand All @@ -19,7 +19,12 @@ New Device Logged In From {{{device}}}
</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">
<b>Device Type:</b> {{device}}
<b>Device Name:</b> {{device_name}}
</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" 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>Device Type:</b> {{device_type}}
</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;">
Expand Down

0 comments on commit e123c93

Please sign in to comment.