Browse Source

perf(mail): send new device login notification in the background

pull/7680/head
BryanFRD 2 days ago
parent
commit
2589d69e9f
  1. 67
      src/api/identity.rs
  2. 14
      src/mail.rs

67
src/api/identity.rs

@ -30,7 +30,7 @@ use crate::{
db::{
DbConn,
models::{
AuthRequest, AuthRequestId, Device, DeviceId, EventType, Invitation, OIDCCodeResponseError,
AuthRequest, AuthRequestId, Device, DeviceId, DeviceType, EventType, Invitation, OIDCCodeResponseError,
OrganizationApiKey, OrganizationId, SendId, SsoAuth, SsoUser, TwoFactor, TwoFactorIncomplete,
TwoFactorType, User, UserId,
},
@ -507,6 +507,39 @@ async fn password_login(
authenticated_response(&user, &mut device, auth_tokens, twofactor_token, conn, ip).await
}
async fn send_new_device_email(user: &User, device: &Device, ip: &ClientIp) -> EmptyResult {
if !CONFIG.mail_enabled() || !device.is_new() {
return Ok(());
}
let now = Utc::now().naive_utc();
let device_type = DeviceType::from_i32(device.atype);
if CONFIG.require_device_email() {
if let Err(e) =
mail::send_new_device_logged_in(&user.email, &ip.ip.to_string(), &now, &device.name, device_type).await
{
error!("Error sending new device email: {e:#?}");
err!(
"Could not send login notification email. Please contact your administrator.",
ErrorEvent {
event: EventType::UserFailedLogIn
}
)
}
return Ok(());
}
let (address, ip, device_name) = (user.email.clone(), ip.ip.to_string(), device.name.clone());
tokio::task::spawn(async move {
if let Err(e) = mail::send_new_device_logged_in(&address, &ip, &now, &device_name, device_type).await {
error!("Error sending new device email: {e:#?}");
}
});
Ok(())
}
async fn authenticated_response(
user: &User,
device: &mut Device,
@ -515,21 +548,7 @@ async fn authenticated_response(
conn: &DbConn,
ip: &ClientIp,
) -> JsonResult {
if CONFIG.mail_enabled() && device.is_new() {
let now = Utc::now().naive_utc();
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:#?}");
if CONFIG.require_device_email() {
err!(
"Could not send login notification email. Please contact your administrator.",
ErrorEvent {
event: EventType::UserFailedLogIn
}
)
}
}
}
send_new_device_email(user, device, ip).await?;
// register push device
if !device.is_new() {
@ -663,21 +682,7 @@ async fn user_api_key_login(
let mut device = get_device(&data, conn, &user).await?;
if CONFIG.mail_enabled() && device.is_new() {
let now = Utc::now().naive_utc();
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:#?}");
if CONFIG.require_device_email() {
err!(
"Could not send login notification email. Please contact your administrator.",
ErrorEvent {
event: EventType::UserFailedLogIn
}
)
}
}
}
send_new_device_email(&user, &device, ip).await?;
// ---
// Disabled this variable, it was used to generate the JWT

14
src/mail.rs

@ -17,7 +17,7 @@ use crate::{
encode_jwt, generate_delete_claims, generate_emergency_access_invite_claims, generate_invite_claims,
generate_verify_email_claims,
},
db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId},
db::models::{DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId},
error::Error,
util::upcase_first,
};
@ -514,7 +514,13 @@ 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: &Device) -> EmptyResult {
pub async fn send_new_device_logged_in(
address: &str,
ip: &str,
dt: &NaiveDateTime,
device_name: &str,
device_type: DeviceType,
) -> EmptyResult {
let fmt = "%A, %B %_d, %Y at %r %Z";
let (subject, body_html, body_text) = get_text(
"email/new_device_logged_in",
@ -522,8 +528,8 @@ 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_name": upcase_first(&device.name),
"device_type": DeviceType::from_i32(device.atype).to_string(),
"device_name": upcase_first(device_name),
"device_type": device_type.to_string(),
"datetime": crate::util::format_naive_datetime_local(dt, fmt),
}),
)?;

Loading…
Cancel
Save