This commit is contained in:
2026-01-07 20:19:26 -05:00
parent 244c8b6fb5
commit f056cf05d3
21 changed files with 2407 additions and 168 deletions

View File

@@ -4,6 +4,9 @@ import { AUTH_CONFIG } from "~/config";
import loginLinkTemplate from "./login-link.html?raw";
import passwordResetTemplate from "./password-reset.html?raw";
import emailVerificationTemplate from "./email-verification.html?raw";
import providerLinkedTemplate from "./provider-linked.html?raw";
import newDeviceLoginTemplate from "./new-device-login.html?raw";
import passwordSetTemplate from "./password-set.html?raw";
/**
* Convert expiry string to human-readable format
@@ -94,3 +97,68 @@ export function generateEmailVerificationEmail(
EXPIRY_TIME: expiryTime
});
}
export interface ProviderLinkedEmailParams {
providerName: string;
providerEmail?: string;
linkTime: string;
deviceInfo: string;
}
/**
* Generate provider linked notification email HTML
*/
export function generateProviderLinkedEmail(
params: ProviderLinkedEmailParams
): string {
return processTemplate(providerLinkedTemplate, {
PROVIDER_NAME: params.providerName,
PROVIDER_EMAIL: params.providerEmail || "N/A",
LINK_TIME: params.linkTime,
DEVICE_INFO: params.deviceInfo
});
}
export interface NewDeviceLoginEmailParams {
deviceInfo: string;
loginTime: string;
ipAddress: string;
loginMethod: string;
accountUrl: string;
}
/**
* Generate new device login notification email HTML
*/
export function generateNewDeviceLoginEmail(
params: NewDeviceLoginEmailParams
): string {
return processTemplate(newDeviceLoginTemplate, {
DEVICE_INFO: params.deviceInfo,
LOGIN_TIME: params.loginTime,
IP_ADDRESS: params.ipAddress,
LOGIN_METHOD: params.loginMethod,
ACCOUNT_URL: params.accountUrl
});
}
export interface PasswordSetEmailParams {
providerName: string;
setTime: string;
deviceInfo: string;
ipAddress: string;
}
/**
* Generate password set notification email HTML
*/
export function generatePasswordSetEmail(
params: PasswordSetEmailParams
): string {
return processTemplate(passwordSetTemplate, {
PROVIDER_NAME: params.providerName,
SET_TIME: params.setTime,
DEVICE_INFO: params.deviceInfo,
IP_ADDRESS: params.ipAddress
});
}

View File

@@ -0,0 +1,131 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>New Device Login</title>
</head>
<body
style="
font-family:
-apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto,
&quot;Helvetica Neue&quot;, Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
"
>
<div
style="
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 30px;
border-radius: 10px 10px 0 0;
text-align: center;
"
>
<h1 style="color: white; margin: 0; font-size: 24px">
New Device Login Detected
</h1>
</div>
<div
style="
background: #ffffff;
padding: 30px;
border: 1px solid #e0e0e0;
border-top: none;
border-radius: 0 0 10px 10px;
"
>
<p style="font-size: 16px; margin-top: 0">Hello,</p>
<p style="font-size: 16px">
We detected a new login to your account from a device we haven't seen
before:
</p>
<div
style="
background: #f8f9fa;
border-left: 4px solid #667eea;
padding: 15px;
margin: 20px 0;
"
>
<p style="margin: 0; font-size: 16px">
<strong>Device:</strong> {{DEVICE_INFO}}
</p>
<p style="margin: 10px 0 0 0; font-size: 14px; color: #666">
<strong>Time:</strong> {{LOGIN_TIME}}
</p>
<p style="margin: 10px 0 0 0; font-size: 14px; color: #666">
<strong>Location:</strong> {{IP_ADDRESS}}
</p>
<p style="margin: 10px 0 0 0; font-size: 14px; color: #666">
<strong>Method:</strong> {{LOGIN_METHOD}}
</p>
</div>
<p style="font-size: 16px">
If this was you, you can safely ignore this email.
</p>
<div
style="
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 5px;
padding: 15px;
margin: 20px 0;
"
>
<p style="margin: 0; font-size: 14px; color: #856404">
<strong>⚠️ Wasn't you?</strong><br />
If you didn't log in from this device, your account may be
compromised. Please sign in immediately and:
</p>
<ul
style="
margin: 10px 0 0 0;
padding-left: 20px;
font-size: 14px;
color: #856404;
"
>
<li>Revoke all active sessions</li>
<li>Change your password</li>
<li>Review linked authentication providers</li>
</ul>
</div>
<div style="text-align: center; margin: 30px 0">
<a
href="{{ACCOUNT_URL}}"
style="
display: inline-block;
background: #667eea;
color: white;
padding: 12px 30px;
text-decoration: none;
border-radius: 5px;
font-weight: bold;
"
>
Review Account Security
</a>
</div>
<p style="font-size: 14px; color: #666; margin-bottom: 0">Best regards</p>
</div>
<div
style="text-align: center; padding: 20px; font-size: 12px; color: #999"
>
<p style="margin: 0">
This is an automated security notification from freno.me
</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,103 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Password Added to Account</title>
</head>
<body
style="
font-family:
-apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto,
&quot;Helvetica Neue&quot;, Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
"
>
<div
style="
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 30px;
border-radius: 10px 10px 0 0;
text-align: center;
"
>
<h1 style="color: white; margin: 0; font-size: 24px">
Password Added to Your Account
</h1>
</div>
<div
style="
background: #ffffff;
padding: 30px;
border: 1px solid #e0e0e0;
border-top: none;
border-radius: 0 0 10px 10px;
"
>
<p style="font-size: 16px; margin-top: 0">Hello,</p>
<p style="font-size: 16px">
A password has been successfully added to your account. You can now sign
in using your email and password in addition to your existing
authentication methods.
</p>
<div
style="
background: #f8f9fa;
border-left: 4px solid #667eea;
padding: 15px;
margin: 20px 0;
"
>
<p style="margin: 0; font-size: 16px">
<strong>Time:</strong> {{SET_TIME}}
</p>
<p style="margin: 10px 0 0 0; font-size: 14px; color: #666">
<strong>Device:</strong> {{DEVICE_INFO}}
</p>
<p style="margin: 10px 0 0 0; font-size: 14px; color: #666">
<strong>IP Address:</strong> {{IP_ADDRESS}}
</p>
</div>
<p style="font-size: 16px">
This provides you with an additional way to access your account and
ensures you can still sign in even if you lose access to your
{{PROVIDER_NAME}} account.
</p>
<div
style="
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 5px;
padding: 15px;
margin: 20px 0;
"
>
<p style="margin: 0; font-size: 14px; color: #856404">
<strong>⚠️ Didn't set this password?</strong><br />
If you didn't perform this action, your account security may be at
risk. Please sign in immediately, change your password, and review
your account settings.
</p>
</div>
<p style="font-size: 14px; color: #666; margin-bottom: 0">Best regards</p>
</div>
<div
style="text-align: center; padding: 20px; font-size: 12px; color: #999"
>
<p style="margin: 0">
This is an automated security notification from freno.me
</p>
</div>
</body>
</html>

View File

@@ -0,0 +1,102 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>New Provider Linked</title>
</head>
<body
style="
font-family:
-apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto,
&quot;Helvetica Neue&quot;, Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 600px;
margin: 0 auto;
padding: 20px;
"
>
<div
style="
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 30px;
border-radius: 10px 10px 0 0;
text-align: center;
"
>
<h1 style="color: white; margin: 0; font-size: 24px">
New Login Method Linked
</h1>
</div>
<div
style="
background: #ffffff;
padding: 30px;
border: 1px solid #e0e0e0;
border-top: none;
border-radius: 0 0 10px 10px;
"
>
<p style="font-size: 16px; margin-top: 0">Hello,</p>
<p style="font-size: 16px">
A new authentication provider has been linked to your account:
</p>
<div
style="
background: #f8f9fa;
border-left: 4px solid #667eea;
padding: 15px;
margin: 20px 0;
"
>
<p style="margin: 0; font-size: 16px">
<strong>Provider:</strong> {{PROVIDER_NAME}}
</p>
<p style="margin: 10px 0 0 0; font-size: 14px; color: #666">
<strong>Email:</strong> {{PROVIDER_EMAIL}}
</p>
<p style="margin: 10px 0 0 0; font-size: 14px; color: #666">
<strong>Time:</strong> {{LINK_TIME}}
</p>
<p style="margin: 10px 0 0 0; font-size: 14px; color: #666">
<strong>Device:</strong> {{DEVICE_INFO}}
</p>
</div>
<p style="font-size: 16px">
You can now sign in to your account using {{PROVIDER_NAME}}.
</p>
<div
style="
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 5px;
padding: 15px;
margin: 20px 0;
"
>
<p style="margin: 0; font-size: 14px; color: #856404">
<strong>⚠️ Didn't link this provider?</strong><br />
If you didn't perform this action, your account security may be at
risk. Please sign in and remove this provider immediately, then change
your password.
</p>
</div>
<p style="font-size: 14px; color: #666; margin-bottom: 0">Best regards</p>
</div>
<div
style="text-align: center; padding: 20px; font-size: 12px; color: #999"
>
<p style="margin: 0">
This is an automated security notification from freno.me
</p>
</div>
</body>
</html>