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::{ db::{
DbConn, DbConn,
models::{ models::{
AuthRequest, AuthRequestId, Device, DeviceId, EventType, Invitation, OIDCCodeResponseError, AuthRequest, AuthRequestId, Device, DeviceId, DeviceType, EventType, Invitation, OIDCCodeResponseError,
OrganizationApiKey, OrganizationId, SendId, SsoAuth, SsoUser, TwoFactor, TwoFactorIncomplete, OrganizationApiKey, OrganizationId, SendId, SsoAuth, SsoUser, TwoFactor, TwoFactorIncomplete,
TwoFactorType, User, UserId, TwoFactorType, User, UserId,
}, },
@ -507,6 +507,39 @@ async fn password_login(
authenticated_response(&user, &mut device, auth_tokens, twofactor_token, conn, ip).await 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( async fn authenticated_response(
user: &User, user: &User,
device: &mut Device, device: &mut Device,
@ -515,21 +548,7 @@ async fn authenticated_response(
conn: &DbConn, conn: &DbConn,
ip: &ClientIp, ip: &ClientIp,
) -> JsonResult { ) -> JsonResult {
if CONFIG.mail_enabled() && device.is_new() { send_new_device_email(user, device, ip).await?;
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
}
)
}
}
}
// register push device // register push device
if !device.is_new() { if !device.is_new() {
@ -663,21 +682,7 @@ async fn user_api_key_login(
let mut device = get_device(&data, conn, &user).await?; let mut device = get_device(&data, conn, &user).await?;
if CONFIG.mail_enabled() && device.is_new() { send_new_device_email(&user, &device, ip).await?;
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
}
)
}
}
}
// --- // ---
// Disabled this variable, it was used to generate the JWT // 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, encode_jwt, generate_delete_claims, generate_emergency_access_invite_claims, generate_invite_claims,
generate_verify_email_claims, generate_verify_email_claims,
}, },
db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, db::models::{DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId},
error::Error, error::Error,
util::upcase_first, 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 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 fmt = "%A, %B %_d, %Y at %r %Z";
let (subject, body_html, body_text) = get_text( let (subject, body_html, body_text) = get_text(
"email/new_device_logged_in", "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(), "url": CONFIG.domain(),
"img_src": CONFIG._smtp_img_src(), "img_src": CONFIG._smtp_img_src(),
"ip": ip, "ip": ip,
"device_name": upcase_first(&device.name), "device_name": upcase_first(device_name),
"device_type": DeviceType::from_i32(device.atype).to_string(), "device_type": device_type.to_string(),
"datetime": crate::util::format_naive_datetime_local(dt, fmt), "datetime": crate::util::format_naive_datetime_local(dt, fmt),
}), }),
)?; )?;

Loading…
Cancel
Save