Actually use Device Type for mails (#4916)

- match Bitwarden behaviour
- add a different segment in mails for Device Name
This commit is contained in:
Daniel 2024-09-18 20:03:15 +03:00 committed by GitHub
parent 1031c2e286
commit 21efc0800d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 57 additions and 21 deletions

View file

@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` DROP COLUMN `device_type`;

View file

@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` ADD COLUMN `device_type` INTEGER NOT NULL;

View file

@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` DROP COLUMN `device_type`;

View file

@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` ADD COLUMN `device_type` INTEGER NOT NULL;

View file

@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` DROP COLUMN `device_type`;

View file

@ -0,0 +1 @@
ALTER TABLE `twofactor_incomplete` ADD COLUMN `device_type` INTEGER NOT NULL;

View file

@ -269,7 +269,13 @@ pub async fn send_incomplete_2fa_notifications(pool: DbPool) {
"User {} did not complete a 2FA login within the configured time limit. IP: {}", "User {} did not complete a 2FA login within the configured time limit. IP: {}",
user.email, login.ip_address user.email, login.ip_address
); );
match mail::send_incomplete_2fa_login(&user.email, &login.ip_address, &login.login_time, &login.device_name) 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 .await
{ {
Ok(_) => { Ok(_) => {

View file

@ -265,7 +265,7 @@ async fn _password_login(
let twofactor_token = twofactor_auth(&user, &data, &mut device, ip, conn).await?; let twofactor_token = twofactor_auth(&user, &data, &mut device, ip, conn).await?;
if CONFIG.mail_enabled() && new_device { 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).await {
error!("Error sending new device email: {:#?}", e); error!("Error sending new device email: {:#?}", e);
if CONFIG.require_device_email() { if CONFIG.require_device_email() {
@ -421,7 +421,7 @@ async fn _user_api_key_login(
if CONFIG.mail_enabled() && new_device { if CONFIG.mail_enabled() && new_device {
let now = Utc::now().naive_utc(); 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).await {
error!("Error sending new device email: {:#?}", e); error!("Error sending new device email: {:#?}", e);
if CONFIG.require_device_email() { if CONFIG.require_device_email() {
@ -535,7 +535,7 @@ async fn twofactor_auth(
return Ok(None); 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 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 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

View file

@ -13,6 +13,7 @@ db_object! {
// must complete 2FA login before being added into the devices table. // must complete 2FA login before being added into the devices table.
pub device_uuid: String, pub device_uuid: String,
pub device_name: String, pub device_name: String,
pub device_type: i32,
pub login_time: NaiveDateTime, pub login_time: NaiveDateTime,
pub ip_address: String, pub ip_address: String,
} }
@ -23,6 +24,7 @@ impl TwoFactorIncomplete {
user_uuid: &str, user_uuid: &str,
device_uuid: &str, device_uuid: &str,
device_name: &str, device_name: &str,
device_type: i32,
ip: &ClientIp, ip: &ClientIp,
conn: &mut DbConn, conn: &mut DbConn,
) -> EmptyResult { ) -> EmptyResult {
@ -44,6 +46,7 @@ impl TwoFactorIncomplete {
twofactor_incomplete::user_uuid.eq(user_uuid), twofactor_incomplete::user_uuid.eq(user_uuid),
twofactor_incomplete::device_uuid.eq(device_uuid), twofactor_incomplete::device_uuid.eq(device_uuid),
twofactor_incomplete::device_name.eq(device_name), 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::login_time.eq(Utc::now().naive_utc()),
twofactor_incomplete::ip_address.eq(ip.ip.to_string()), twofactor_incomplete::ip_address.eq(ip.ip.to_string()),
)) ))

View file

@ -169,6 +169,7 @@ table! {
user_uuid -> Text, user_uuid -> Text,
device_uuid -> Text, device_uuid -> Text,
device_name -> Text, device_name -> Text,
device_type -> Integer,
login_time -> Timestamp, login_time -> Timestamp,
ip_address -> Text, ip_address -> Text,
} }

View file

@ -169,6 +169,7 @@ table! {
user_uuid -> Text, user_uuid -> Text,
device_uuid -> Text, device_uuid -> Text,
device_name -> Text, device_name -> Text,
device_type -> Integer,
login_time -> Timestamp, login_time -> Timestamp,
ip_address -> Text, ip_address -> Text,
} }

View file

@ -169,6 +169,7 @@ table! {
user_uuid -> Text, user_uuid -> Text,
device_uuid -> Text, device_uuid -> Text,
device_name -> Text, device_name -> Text,
device_type -> Integer,
login_time -> Timestamp, login_time -> Timestamp,
ip_address -> Text, ip_address -> Text,
} }

View file

@ -17,7 +17,7 @@ use crate::{
encode_jwt, generate_delete_claims, generate_emergency_access_invite_claims, generate_invite_claims, encode_jwt, generate_delete_claims, generate_emergency_access_invite_claims, generate_invite_claims,
generate_verify_email_claims, generate_verify_email_claims,
}, },
db::models::User, db::models::{Device, DeviceType, User},
error::Error, error::Error,
CONFIG, CONFIG,
}; };
@ -442,9 +442,8 @@ pub async fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult
send_email(address, &subject, body_html, body_text).await 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: &Device) -> EmptyResult {
use crate::util::upcase_first; use crate::util::upcase_first;
let device = upcase_first(device);
let fmt = "%A, %B %_d, %Y at %r %Z"; let fmt = "%A, %B %_d, %Y at %r %Z";
let (subject, body_html, body_text) = get_text( let (subject, body_html, body_text) = get_text(
@ -453,7 +452,8 @@ pub async fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTi
"url": CONFIG.domain(), "url": CONFIG.domain(),
"img_src": CONFIG._smtp_img_src(), "img_src": CONFIG._smtp_img_src(),
"ip": ip, "ip": ip,
"device": device, "device_name": upcase_first(&device.name),
"device_type": DeviceType::from_i32(device.atype).to_string(),
"datetime": crate::util::format_naive_datetime_local(dt, fmt), "datetime": crate::util::format_naive_datetime_local(dt, fmt),
}), }),
)?; )?;
@ -461,9 +461,14 @@ pub async fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTi
send_email(address, &subject, body_html, body_text).await 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; use crate::util::upcase_first;
let device = upcase_first(device);
let fmt = "%A, %B %_d, %Y at %r %Z"; let fmt = "%A, %B %_d, %Y at %r %Z";
let (subject, body_html, body_text) = get_text( let (subject, body_html, body_text) = get_text(
@ -472,7 +477,8 @@ pub async fn send_incomplete_2fa_login(address: &str, ip: &str, dt: &NaiveDateTi
"url": CONFIG.domain(), "url": CONFIG.domain(),
"img_src": CONFIG._smtp_img_src(), "img_src": CONFIG._smtp_img_src(),
"ip": ip, "ip": ip,
"device": device, "device_name": upcase_first(device_name),
"device_type": device_type,
"datetime": crate::util::format_naive_datetime_local(dt, fmt), "datetime": crate::util::format_naive_datetime_local(dt, fmt),
"time_limit": CONFIG.incomplete_2fa_time_limit(), "time_limit": CONFIG.incomplete_2fa_time_limit(),
}), }),

View file

@ -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. 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}} * Date: {{datetime}}
* IP Address: {{ip}} * 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. 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 }} {{> email/email_footer_text }}

View file

@ -1,4 +1,4 @@
Incomplete Two-Step Login From {{{device}}} Incomplete Two-Step Login From {{{device_name}}}
<!----------------> <!---------------->
{{> email/email_header }} {{> 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;"> <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;">
@ -19,7 +19,12 @@ Incomplete Two-Step Login From {{{device}}}
</tr> </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;"> <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"> <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> </td>
</tr> </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;"> <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;">

View file

@ -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. Your account was just logged into from a new device.
* Date: {{datetime}} * Date: {{datetime}}
* IP Address: {{ip}} * 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. 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 }}

View file

@ -1,4 +1,4 @@
New Device Logged In From {{{device}}} New Device Logged In From {{{device_name}}}
<!----------------> <!---------------->
{{> email/email_header }} {{> 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;"> <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;">
@ -19,7 +19,12 @@ New Device Logged In From {{{device}}}
</tr> </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;"> <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"> <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> </td>
</tr> </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;"> <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;">