diff options
| author | Brynn Crowley <littlehill723@gmail.com> | 2024-09-22 01:48:55 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-22 18:48:55 +1000 |
| commit | ef303022423feca3a570efd17747fe39bd97c1e9 (patch) | |
| tree | c0a830ed2c488bc5df048170684027d1719d98a5 | |
| parent | c9b40a0c60ee3f5889dfa5fd03db6f769c9e2761 (diff) | |
fix(templates): grammar and enhancements to emails (#7903)
* fix: grammar and minor changes to email templates
* fix(handlers): fix failing session-elevation test
19 files changed, 95 insertions, 17 deletions
diff --git a/internal/handlers/handler_register_totp.go b/internal/handlers/handler_register_totp.go index b542e3b97..8abebaeca 100644 --- a/internal/handlers/handler_register_totp.go +++ b/internal/handlers/handler_register_totp.go @@ -251,7 +251,13 @@ func TOTPRegisterPOST(ctx *middlewares.AutheliaCtx) { return } - ctxLogEvent(ctx, userSession.Username, eventLogAction2FAAdded, map[string]any{eventLogKeyAction: eventLogAction2FAAdded, eventLogKeyCategory: eventLogCategoryOneTimePassword}) + body := emailEventBody{ + Prefix: eventEmailAction2FAPrefix, + Body: eventEmailAction2FABody, + Suffix: eventEmailAction2FAAddedSuffix, + } + + ctxLogEvent(ctx, userSession.Username, eventLogAction2FAAdded, body, map[string]any{eventLogKeyAction: eventLogAction2FAAdded, eventLogKeyCategory: eventLogCategoryOneTimePassword}) ctx.ReplyOK() } @@ -344,7 +350,13 @@ func TOTPConfigurationDELETE(ctx *middlewares.AutheliaCtx) { return } - ctxLogEvent(ctx, userSession.Username, eventLogAction2FARemoved, map[string]any{eventLogKeyAction: eventLogAction2FARemoved, eventLogKeyCategory: eventLogCategoryOneTimePassword}) + body := emailEventBody{ + Prefix: eventEmailAction2FAPrefix, + Body: eventEmailAction2FABody, + Suffix: eventEmailAction2FARemovedSuffix, + } + + ctxLogEvent(ctx, userSession.Username, eventLogAction2FARemoved, body, map[string]any{eventLogKeyAction: eventLogAction2FARemoved, eventLogKeyCategory: eventLogCategoryOneTimePassword}) ctx.ReplyOK() } diff --git a/internal/handlers/handler_register_webauthn.go b/internal/handlers/handler_register_webauthn.go index 0423f8124..e4ba58cae 100644 --- a/internal/handlers/handler_register_webauthn.go +++ b/internal/handlers/handler_register_webauthn.go @@ -235,7 +235,13 @@ func WebAuthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { ctx.ReplyOK() ctx.SetStatusCode(fasthttp.StatusCreated) - ctxLogEvent(ctx, userSession.Username, eventLogAction2FAAdded, map[string]any{eventLogKeyAction: eventLogAction2FAAdded, eventLogKeyCategory: eventLogCategoryWebAuthnCredential, eventLogKeyDescription: credential.Description}) + body := emailEventBody{ + Prefix: eventEmailAction2FAPrefix, + Body: eventEmailAction2FABody, + Suffix: eventEmailAction2FAAddedSuffix, + } + + ctxLogEvent(ctx, userSession.Username, eventLogAction2FAAdded, body, map[string]any{eventLogKeyAction: eventLogAction2FAAdded, eventLogKeyCategory: eventLogCategoryWebAuthnCredential, eventLogKeyDescription: credential.Description}) } // WebAuthnRegistrationDELETE deletes any active WebAuthn registration session.. diff --git a/internal/handlers/handler_reset_password.go b/internal/handlers/handler_reset_password.go index 56f23c3ad..2e9b3da3e 100644 --- a/internal/handlers/handler_reset_password.go +++ b/internal/handlers/handler_reset_password.go @@ -198,6 +198,9 @@ func ResetPasswordPOST(ctx *middlewares.AutheliaCtx) { Details: map[string]any{ "Action": "Password Reset", }, + BodyPrefix: eventEmailActionPasswordResetPrefix, + BodyEvent: eventEmailActionPasswordReset, + BodySuffix: eventEmailActionPasswordResetSuffix, } addresses := userInfo.Addresses() diff --git a/internal/handlers/handler_session_elevation.go b/internal/handlers/handler_session_elevation.go index 1b5e6801b..6c138c489 100644 --- a/internal/handlers/handler_session_elevation.go +++ b/internal/handlers/handler_session_elevation.go @@ -177,12 +177,15 @@ func UserSessionElevationPOST(ctx *middlewares.AutheliaCtx) { identity := userSession.Identity() + domain, _ := ctx.GetCookieDomain() + data := templates.EmailIdentityVerificationOTCValues{ Title: "Confirm your identity", RevocationLinkURL: linkURL.String(), RevocationLinkText: "Revoke", DisplayName: identity.DisplayName, RemoteIP: ctx.RemoteIP().String(), + Domain: domain, OneTimeCode: string(otp.Code), } diff --git a/internal/handlers/handler_session_elevation_test.go b/internal/handlers/handler_session_elevation_test.go index 809c50a16..76d83c799 100644 --- a/internal/handlers/handler_session_elevation_test.go +++ b/internal/handlers/handler_session_elevation_test.go @@ -360,6 +360,7 @@ func TestUserSessionElevationPOST(t *testing.T) { RevocationLinkURL: "http://example.com/revoke/one-time-code?id=AQIDBAUGRyKJEBESExQVAA", RevocationLinkText: "Revoke", DisplayName: testDisplayName, + Domain: "example.com", RemoteIP: "0.0.0.0", OneTimeCode: "ABC123ABC1", }). @@ -409,6 +410,7 @@ func TestUserSessionElevationPOST(t *testing.T) { RevocationLinkURL: "http://example.com/revoke/one-time-code?id=AQIDBAUGRyKJEBESExQVAA", RevocationLinkText: "Revoke", DisplayName: testDisplayName, + Domain: "example.com", RemoteIP: "0.0.0.0", OneTimeCode: "ABC123ABC1", }). diff --git a/internal/handlers/handler_webauthn_credentials.go b/internal/handlers/handler_webauthn_credentials.go index 75ecba58c..c465cad1a 100644 --- a/internal/handlers/handler_webauthn_credentials.go +++ b/internal/handlers/handler_webauthn_credentials.go @@ -266,7 +266,13 @@ func WebAuthnCredentialDELETE(ctx *middlewares.AutheliaCtx) { return } - ctxLogEvent(ctx, userSession.Username, eventLogAction2FARemoved, map[string]any{eventLogKeyAction: eventLogAction2FARemoved, eventLogKeyCategory: eventLogCategoryWebAuthnCredential, eventLogKeyDescription: credential.Description}) + body := emailEventBody{ + Prefix: eventEmailAction2FAPrefix, + Body: eventEmailAction2FABody, + Suffix: eventEmailAction2FARemovedSuffix, + } + + ctxLogEvent(ctx, userSession.Username, eventLogAction2FARemoved, body, map[string]any{eventLogKeyAction: eventLogAction2FARemoved, eventLogKeyCategory: eventLogCategoryWebAuthnCredential, eventLogKeyDescription: credential.Description}) ctx.ReplyOK() } diff --git a/internal/handlers/util.go b/internal/handlers/util.go index 11968db6f..9a137f6a1 100644 --- a/internal/handlers/util.go +++ b/internal/handlers/util.go @@ -13,14 +13,29 @@ const ( eventLogKeyCategory = "Category" eventLogKeyDescription = "Description" + eventEmailAction2FABody = "Second Factor Method" eventLogAction2FAAdded = "Second Factor Method Added" eventLogAction2FARemoved = "Second Factor Method Removed" + eventEmailAction2FAPrefix = "a" + eventEmailAction2FAAddedSuffix = "was added to your account." + eventEmailAction2FARemovedSuffix = "was removed from your account." + + eventEmailActionPasswordResetPrefix = "your" + eventEmailActionPasswordReset = "Password Reset" + eventEmailActionPasswordResetSuffix = "was successful." + eventLogCategoryOneTimePassword = "One-Time Password" eventLogCategoryWebAuthnCredential = "WebAuthn Credential" //nolint:gosec ) -func ctxLogEvent(ctx *middlewares.AutheliaCtx, username, description string, eventDetails map[string]any) { +type emailEventBody struct { + Prefix string + Body string + Suffix string +} + +func ctxLogEvent(ctx *middlewares.AutheliaCtx, username, description string, body emailEventBody, eventDetails map[string]any) { var ( details *authentication.UserDetails err error @@ -44,6 +59,9 @@ func ctxLogEvent(ctx *middlewares.AutheliaCtx, username, description string, eve DisplayName: details.DisplayName, RemoteIP: ctx.RemoteIP().String(), Details: eventDetails, + BodyPrefix: body.Prefix, + BodyEvent: body.Body, + BodySuffix: body.Suffix, } ctx.Logger.Debugf("Getting user addresses for notification") diff --git a/internal/middlewares/identity_verification.go b/internal/middlewares/identity_verification.go index 066aac3f4..faabe8369 100644 --- a/internal/middlewares/identity_verification.go +++ b/internal/middlewares/identity_verification.go @@ -93,6 +93,8 @@ func IdentityVerificationStart(args IdentityVerificationStartArgs, delayFunc Tim revocationLinkURL.Path = path.Join(revocationLinkURL.Path, args.RevokeEndpoint) revocationLinkURL.RawQuery = query.Encode() + domain, _ := ctx.GetCookieDomain() + data := templates.EmailIdentityVerificationJWTValues{ Title: args.MailTitle, LinkURL: linkURL.String(), @@ -100,6 +102,7 @@ func IdentityVerificationStart(args IdentityVerificationStartArgs, delayFunc Tim RevocationLinkURL: revocationLinkURL.String(), RevocationLinkText: args.MailButtonRevokeContent, DisplayName: identity.DisplayName, + Domain: domain, RemoteIP: ctx.RemoteIP().String(), } diff --git a/internal/templates/embed/notification/Event.html b/internal/templates/embed/notification/Event.html index a626aa00e..f5a867034 100644 --- a/internal/templates/embed/notification/Event.html +++ b/internal/templates/embed/notification/Event.html @@ -1 +1 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html dir="ltr" lang="en"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/></head><div style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">An important event has occurred with your account<div> </div></div><body style="background-color:rgb(255,255,255);margin-top:auto;margin-bottom:auto;margin-left:auto;margin-right:auto;font-family:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";padding-left:0.5rem;padding-right:0.5rem"><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);border-radius:0.25rem;margin-top:40px;margin-bottom:40px;margin-left:auto;margin-right:auto;padding:20px;max-width:465px"><tbody><tr style="width:100%"><td><p style="color:rgb(0,0,0);font-size:24px;font-weight:400;text-align:center;padding:0px;margin-top:30px;margin-bottom:30px;margin-left:0px;margin-right:0px;line-height:24px;margin:16px 0">{{ .Title }}</p><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">Hi <!-- -->{{ .DisplayName }}<!-- -->,</p><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">This notification has been sent to you in order to notify you that a new <strong><i>{{ .Title }}</i></strong></p><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:26px;margin-bottom:26px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/><p style="font-size:14px;line-height:24px;margin:16px 0">Event Details:</p><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin:0.5rem"><tbody><tr><td>{{- $keys := sortAlpha (keys .Details) }}{{- range $key := $keys }}<p style="font-size:14px;line-height:24px;margin:16px 0"><strong>{{ $key }}<!-- -->:</strong> <!-- -->{{ index $.Details $key }}</p>{{ end }}</td></tr></tbody></table><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:26px;margin-bottom:26px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/><p style="color:rgb(102,102,102);font-size:12px;line-height:24px;text-align:center;margin:16px 0">This notification was intended for <span style="color:rgb(0,0,0)">{{ .DisplayName }}</span>. This event notification was generated due to an action from <span style="color:rgb(0,0,0)">{{ .RemoteIP }}</span>. If you do not believe that your actions could have triggered this event or if you are concerned about your account's safety, please change your password and reach out to an administrator.</p></td></tr></tbody></table><p class="text-muted" style="color:rgb(102,102,102);font-size:10px;line-height:24px;text-align:center;margin:16px 0">Powered by <a href="https://www.authelia.com" style="color:rgb(102,102,102);text-decoration:none" target="_blank">Authelia</a></p></body></html>
\ No newline at end of file +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><html dir="ltr" lang="en"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/></head><div style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">An important event has occurred with your account<div> </div></div><body style="background-color:rgb(255,255,255);margin-top:auto;margin-bottom:auto;margin-left:auto;margin-right:auto;font-family:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";padding-left:0.5rem;padding-right:0.5rem"><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);border-radius:0.25rem;margin-top:40px;margin-bottom:40px;margin-left:auto;margin-right:auto;padding:20px;max-width:465px"><tbody><tr style="width:100%"><td><p style="color:rgb(0,0,0);font-size:24px;font-weight:400;text-align:center;padding:0px;margin-top:30px;margin-bottom:30px;margin-left:0px;margin-right:0px;line-height:24px;margin:16px 0">{{ .Title }}</p><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">Hi <!-- -->{{ .DisplayName }}<!-- -->,</p><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">This notification has been sent to you in order to notify you that <!-- -->{{ .BodyPrefix }}<!-- --> <strong><i>{{ .BodyEvent }}</i></strong> <!-- -->{{ .BodySuffix }}</p><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:26px;margin-bottom:26px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/><p style="font-size:14px;line-height:24px;margin:16px 0">Event Details:</p><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="margin:0.5rem"><tbody><tr><td>{{- $keys := sortAlpha (keys .Details) }}{{- range $key := $keys }}<p style="font-size:14px;line-height:24px;margin:16px 0"><strong>{{ $key }}<!-- -->:</strong> <!-- -->{{ index $.Details $key }}</p>{{ end }}</td></tr></tbody></table><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:26px;margin-bottom:26px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/><p style="color:rgb(102,102,102);font-size:12px;line-height:24px;text-align:center;margin:16px 0">This notification was intended for <span style="color:rgb(0,0,0)">{{ .DisplayName }}</span>. This event notification was generated due to an action from <span style="color:rgb(0,0,0)">{{ .RemoteIP }}</span>. If you do not believe that your actions could have triggered this event or if you are concerned about your account's safety, please change your password and reach out to an administrator.</p></td></tr></tbody></table><p class="text-muted" style="color:rgb(102,102,102);font-size:10px;line-height:24px;text-align:center;margin:16px 0">Powered by <a href="https://www.authelia.com" style="color:rgb(102,102,102);text-decoration:none" target="_blank">Authelia</a></p></body></html><!--/$-->
\ No newline at end of file diff --git a/internal/templates/embed/notification/Event.txt b/internal/templates/embed/notification/Event.txt index 2e8204378..d96bfa685 100644 --- a/internal/templates/embed/notification/Event.txt +++ b/internal/templates/embed/notification/Event.txt @@ -2,8 +2,8 @@ Hi {{ .DisplayName }}, -This notification has been sent to you in order to notify you that a new {{ -.Title }} +This notification has been sent to you in order to notify you that {{ +.BodyPrefix }} {{ .BodyEvent }} {{ .BodySuffix }} -------------------------------------------------------------------------------- diff --git a/internal/templates/embed/notification/IdentityVerificationJWT.html b/internal/templates/embed/notification/IdentityVerificationJWT.html index 1769113b4..44a5545e1 100644 --- a/internal/templates/embed/notification/IdentityVerificationJWT.html +++ b/internal/templates/embed/notification/IdentityVerificationJWT.html @@ -1 +1 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html dir="ltr" lang="en"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/></head><div style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">{{ .Title }}<div> </div></div><body style="background-color:rgb(255,255,255);margin-top:auto;margin-bottom:auto;margin-left:auto;margin-right:auto;font-family:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";padding-left:0.5rem;padding-right:0.5rem"><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);border-radius:0.25rem;margin-top:40px;margin-bottom:40px;margin-left:auto;margin-right:auto;padding:20px;max-width:465px"><tbody><tr style="width:100%"><td><h1 style="color:rgb(0,0,0);font-size:24px;font-weight:400;text-align:center;padding:0px;margin-top:30px;margin-bottom:30px;margin-left:0px;margin-right:0px">A <strong>one-time link</strong> has been generated to complete a requested action</h1><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">Hi <!-- -->{{ .DisplayName }}<!-- -->,</p><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">We would like to confirm a<!-- --> <strong>requested action </strong>related to the<!-- --> <strong>security of your account</strong> at<!-- --> <i>EXAMPLE.COM.</i><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;text-align:center;margin:16px 0"><strong>Do not share this notification or the content of this notification with anyone.</strong></p></p><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:12px;margin-bottom:12px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="text-align:center"><tbody><tr><td><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">If you made this request, click the validation link below.</p></td></tr></tbody></table><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="text-align:center"><tbody><tr><td><a id="link" href="{{ .LinkURL }}" style="background-color:rgb(25,118,210);border-radius:0.25rem;color:rgb(255,255,255);font-size:12px;font-weight:600;text-decoration-line:none;text-align:center;padding-left:1.25rem;padding-right:1.25rem;padding-top:0.75rem;padding-bottom:0.75rem;line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;padding:12px 20px 12px 20px" target="_blank"><span><!--[if mso]><i style="mso-font-width:500%;mso-text-raise:18" hidden>  </i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px">{{ .LinkText }}</span><span><!--[if mso]><i style="mso-font-width:500%" hidden>  ​</i><![endif]--></span></a></td></tr></tbody></table><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;text-align:center;margin:16px 0">Alternatively, copy and paste this URL into your browser:</p><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="text-align:center"><tbody><tr><td><a href="{{ .LinkURL }}" style="color:rgb(37,99,235);text-decoration-line:none;text-decoration:none" target="_blank">{{ .LinkURL }}</a></td></tr></tbody></table><p style="font-size:14px;line-height:24px;margin:16px 0"><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:26px;margin-bottom:26px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/>If you did NOT initiate this request, your credentials may have been compromised and you should:</p><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="color:rgb(0,0,0);font-size:14px;line-height:22px"><tbody><tr><td><ol><li>Revoke the validation link using the provided links below</li><li>Reset your password or other login credentials</li><li>Contact an Administrator</li></ol></td></tr></tbody></table><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="text-align:center"><tbody><tr><td><a id="link-revoke" href="{{ .RevocationLinkURL }}" style="background-color:rgb(245,0,87);border-radius:0.25rem;color:rgb(255,255,255);font-size:12px;font-weight:600;text-decoration-line:none;text-align:center;padding-left:1.25rem;padding-right:1.25rem;padding-top:0.75rem;padding-bottom:0.75rem;line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;padding:12px 20px 12px 20px" target="_blank"><span><!--[if mso]><i style="mso-font-width:500%;mso-text-raise:18" hidden>  </i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px">{{ .RevocationLinkText }}</span><span><!--[if mso]><i style="mso-font-width:500%" hidden>  ​</i><![endif]--></span></a></td></tr></tbody></table><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">To revoke the code click the above button or alternatively copy and paste this URL into your browser:</p><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;text-align:center;margin:16px 0"><a href="{{ .RevocationLinkURL }}" style="color:rgb(37,99,235);text-decoration-line:none;text-decoration:none" target="_blank">{{ .RevocationLinkURL }}</a></p><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:26px;margin-bottom:26px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/><p style="color:rgb(102,102,102);font-size:12px;line-height:24px;text-align:center;margin:16px 0">This email was intended for<!-- --> <span style="color:rgb(0,0,0)">{{ .DisplayName }}</span>. This event was generated due to an action from<!-- --> <span style="color:rgb(0,0,0)">{{ .RemoteIP }}</span>. If you do not believe that your actions could have triggered this event or if you are concerned about your account's safety, please follow the explicit directions in this notification.</p></td></tr></tbody></table><p class="text-muted" style="color:rgb(102,102,102);font-size:10px;line-height:24px;text-align:center;margin:16px 0">Powered by<!-- --> <a href="https://www.authelia.com" style="color:rgb(102,102,102);text-decoration:none" target="_blank">Authelia</a></p></body></html>
\ No newline at end of file +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><html dir="ltr" lang="en"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/><meta name="x-apple-disable-message-reformatting"/></head><div style="display:none;overflow:hidden;line-height:1px;opacity:0;max-height:0;max-width:0">{{ .Title }}<div> </div></div><body style="background-color:rgb(255,255,255);margin-top:auto;margin-bottom:auto;margin-left:auto;margin-right:auto;font-family:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";padding-left:0.5rem;padding-right:0.5rem"><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);border-radius:0.25rem;margin-top:40px;margin-bottom:40px;margin-left:auto;margin-right:auto;padding:20px;max-width:465px"><tbody><tr style="width:100%"><td><h1 style="color:rgb(0,0,0);font-size:24px;font-weight:400;text-align:center;padding:0px;margin-top:30px;margin-bottom:30px;margin-left:0px;margin-right:0px">A <strong>one-time link</strong> has been generated to complete a requested action</h1><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">Hi <!-- -->{{ .DisplayName }}<!-- -->,</p><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">We would like to confirm a<!-- --> <strong>requested action </strong>related to the<!-- --> <strong>security of your account</strong> at<!-- --> <i>{{ .Domain }}</i><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;text-align:center;margin:16px 0"><strong>Do not share this notification or the content of this notification with anyone.</strong></p></p><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:12px;margin-bottom:12px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="text-align:center"><tbody><tr><td><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">If you made this request, click the validation link below.</p></td></tr></tbody></table><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="text-align:center"><tbody><tr><td><a id="link" href="{{ .LinkURL }}" style="background-color:rgb(25,118,210);border-radius:0.25rem;color:rgb(255,255,255);font-size:12px;font-weight:600;text-decoration-line:none;text-align:center;padding-left:1.25rem;padding-right:1.25rem;padding-top:0.75rem;padding-bottom:0.75rem;line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;padding:12px 20px 12px 20px" target="_blank"><span><!--[if mso]><i style="mso-font-width:500%;mso-text-raise:18" hidden>  </i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px">{{ .LinkText }}</span><span><!--[if mso]><i style="mso-font-width:500%" hidden>  ​</i><![endif]--></span></a></td></tr></tbody></table><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;text-align:center;margin:16px 0">Alternatively, copy and paste this URL into your browser:</p><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="text-align:center"><tbody><tr><td><a href="{{ .LinkURL }}" style="color:rgb(37,99,235);font-size:12px;text-decoration-line:none;text-decoration:none" target="_blank">{{ .LinkURL }}</a></td></tr></tbody></table><p style="font-size:14px;line-height:24px;margin:16px 0"><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:26px;margin-bottom:26px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/>If you did NOT initiate this request, your credentials may have been compromised and you should:</p><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="color:rgb(0,0,0);font-size:14px;line-height:22px"><tbody><tr><td><ol><li>Revoke the validation link using the provided links below</li><li>Reset your password or other login credentials</li><li>Contact an Administrator</li></ol></td></tr></tbody></table><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation" style="text-align:center"><tbody><tr><td><a id="link-revoke" href="{{ .RevocationLinkURL }}" style="background-color:rgb(245,0,87);border-radius:0.25rem;color:rgb(255,255,255);font-size:12px;font-weight:600;text-decoration-line:none;text-align:center;padding-left:1.25rem;padding-right:1.25rem;padding-top:0.75rem;padding-bottom:0.75rem;line-height:100%;text-decoration:none;display:inline-block;max-width:100%;mso-padding-alt:0px;padding:12px 20px 12px 20px" target="_blank"><span><!--[if mso]><i style="mso-font-width:500%;mso-text-raise:18" hidden>  </i><![endif]--></span><span style="max-width:100%;display:inline-block;line-height:120%;mso-padding-alt:0px;mso-text-raise:9px">{{ .RevocationLinkText }}</span><span><!--[if mso]><i style="mso-font-width:500%" hidden>  ​</i><![endif]--></span></a></td></tr></tbody></table><p style="color:rgb(0,0,0);font-size:14px;line-height:24px;margin:16px 0">To revoke the code click the above button or alternatively copy and paste this URL into your browser:</p><p style="color:rgb(0,0,0);font-size:12px;line-height:24px;text-align:center;margin:16px 0"><a href="{{ .RevocationLinkURL }}" style="color:rgb(37,99,235);text-decoration-line:none;text-decoration:none" target="_blank">{{ .RevocationLinkURL }}</a></p><hr style="border-width:1px;border-style:solid;border-color:rgb(234,234,234);margin-top:26px;margin-bottom:26px;margin-left:0px;margin-right:0px;width:100%;border:none;border-top:1px solid #eaeaea"/><p style="color:rgb(102,102,102);font-size:12px;line-height:24px;text-align:center;margin:16px 0">This email was intended for<!-- --> <span style="color:rgb(0,0,0)">{{ .DisplayName }}</span>. This event was generated due to an action from<!-- --> <span style="color:rgb(0,0,0)">{{ .RemoteIP }}</span>. If you do not believe that your actions could have triggered this event or if you are concerned about your account's safety, please follow the explicit directions in this notification.</p></td></tr></tbody></table><p class="text-muted" style="color:rgb(102,102,102);font-size:10px;line-height:24px;text-align:center;margin:16px 0">Powered by<!-- --> <a href="https://www.authelia.com" style="color:rgb(102,102,102);text-decoration:none" target="_blank">Authelia</a></p></body></html><!--/$-->
\ No newline at end of file diff --git a/internal/templates/embed/notification/IdentityVerificationJWT.txt b/internal/templates/embed/notification/IdentityVerificationJWT.txt index d39752708..d53d5aa58 100644 --- a/internal/templates/embed/notification/IdentityVerificationJWT.txt +++ b/internal/templates/embed/notification/IdentityVerificationJWT.txt @@ -3,7 +3,7 @@ A ONE-TIME LINK HAS BEEN GENERATED TO COMPLETE A REQUESTED ACTION Hi {{ .DisplayName }}, We would like to confirm a requested action related to the security of your -account at EXAMPLE.COM. +account at {{ .Domain }} Do not share this notification or the content of this notification with anyone. diff --git a/internal/templates/embed/notification/IdentityVerificationOTC.html b/internal/templates/embed/notification/IdentityVerificationOTC.html Binary files differindex 9e4cd4245..90d1f3096 100644 --- a/internal/templates/embed/notification/IdentityVerificationOTC.html +++ b/internal/templates/embed/notification/IdentityVerificationOTC.html diff --git a/internal/templates/embed/notification/IdentityVerificationOTC.txt b/internal/templates/embed/notification/IdentityVerificationOTC.txt index 098142c35..aba69f755 100644 --- a/internal/templates/embed/notification/IdentityVerificationOTC.txt +++ b/internal/templates/embed/notification/IdentityVerificationOTC.txt @@ -3,7 +3,7 @@ A ONE-TIME CODE HAS BEEN GENERATED TO COMPLETE A REQUESTED ACTION Hi {{ .DisplayName }}, This notification has been sent to you in order to verify your identity to -change security details for your account. +change security details for your account at {{ .Domain }}. Do not share this notification or the content of this notification with anyone. diff --git a/internal/templates/src/emails/Event.tsx b/internal/templates/src/emails/Event.tsx index cdc6a2993..5def6d713 100644 --- a/internal/templates/src/emails/Event.tsx +++ b/internal/templates/src/emails/Event.tsx @@ -13,6 +13,9 @@ import * as React from "react"; interface EventProps { title?: string; + bodyEvent?: string; + bodyPrefix?: string; + bodySuffix?: string; displayName?: string; remoteIP?: string; detailsKey?: string; @@ -23,6 +26,9 @@ interface EventProps { export const Event = ({ title, + bodyEvent, + bodyPrefix, + bodySuffix, displayName, remoteIP, detailsKey, @@ -42,7 +48,7 @@ export const Event = ({ Hi {displayName}, </Text> <Text className="text-black text-[14px] leading-[24px]"> - This notification has been sent to you in order to notify you that a new <strong><i>{title}</i></strong> + This notification has been sent to you in order to notify you that {bodyPrefix} <strong><i>{bodyEvent}</i></strong> {bodySuffix} </Text> <Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" /> <Text>Event Details:</Text> @@ -74,6 +80,9 @@ Event.PreviewProps = { detailsKey: "Example Detail", detailsValue: "Example Value", title: "Second Factor Method Added", + bodyEvent: "Second Factor Method", + bodyPrefix: "a", + bodySuffix: "was added to your account.", remoteIP: "127.0.0.1", } as EventProps; diff --git a/internal/templates/src/emails/IdentityVerificationJWT.tsx b/internal/templates/src/emails/IdentityVerificationJWT.tsx index 24c1e4277..3fedcb392 100644 --- a/internal/templates/src/emails/IdentityVerificationJWT.tsx +++ b/internal/templates/src/emails/IdentityVerificationJWT.tsx @@ -17,6 +17,7 @@ import * as React from 'react'; interface IdentityVerificationJWTProps { title?: string; displayName?: string; + domain?: string; remoteIP?: string; link?: string; linkText?: string; @@ -27,6 +28,7 @@ interface IdentityVerificationJWTProps { export const IdentityVerificationJWT = ({ title, displayName, + domain, remoteIP, link, linkText, @@ -51,7 +53,7 @@ export const IdentityVerificationJWT = ({ We would like to confirm a{' '} <strong>requested action </strong>related to the{' '} <strong>security of your account</strong> at{' '} - <i>EXAMPLE.COM.</i> + <i>{domain}</i> <Text className="text-black text-[14px] leading-[24px] text-center"> <strong> Do not share this notification or the @@ -83,7 +85,7 @@ export const IdentityVerificationJWT = ({ <Section className="text-center"> <Link href={link} - className="text-blue-600 no-underline" + className="text-blue-600 text-[12px] no-underline" > {link} </Link> @@ -123,7 +125,7 @@ export const IdentityVerificationJWT = ({ alternatively copy and paste this URL into your browser: </Text> - <Text className="text-black text-[14px] leading-[24px] text-center"> + <Text className="text-black text-[12px] leading-[24px] text-center"> <Link href={revocationLinkURL} className="text-blue-600 no-underline" @@ -162,6 +164,7 @@ export const IdentityVerificationJWT = ({ IdentityVerificationJWT.PreviewProps = { title: 'Reset your password', displayName: 'John Doe', + domain: 'example.com', link: 'https://auth.example.com', linkText: 'Validate', revocationLinkURL: 'https://auth.example.com', diff --git a/internal/templates/src/emails/IdentityVerificationOTC.tsx b/internal/templates/src/emails/IdentityVerificationOTC.tsx index b8d9a3afc..d2150066f 100644 --- a/internal/templates/src/emails/IdentityVerificationOTC.tsx +++ b/internal/templates/src/emails/IdentityVerificationOTC.tsx @@ -17,6 +17,7 @@ import * as React from 'react'; interface IdentityVerificationOTCProps { title?: string; displayName?: string; + domain?: string; remoteIP?: string; oneTimeCode?: string; revocationLinkURL?: string; @@ -26,6 +27,7 @@ interface IdentityVerificationOTCProps { export const IdentityVerificationOTC = ({ title, displayName, + domain, remoteIP, oneTimeCode, revocationLinkURL, @@ -51,7 +53,7 @@ export const IdentityVerificationOTC = ({ This notification has been sent to you in order to verify your identity to{' '} <strong>change security details</strong> for your - account.{' '} + account at <i>{domain}</i>.{' '} </Text> <Text className="text-black text-[14px] leading-[24px] text-center"> <strong> @@ -107,7 +109,7 @@ export const IdentityVerificationOTC = ({ alternatively copy and paste this URL into your browser:{' '} </Text> - <Text className="text-black text-[14px] leading-[24px] text-center"> + <Text className="text-black text-[12px] leading-[24px] text-center"> <Link href={revocationLinkURL} className="text-blue-600 no-underline" @@ -146,6 +148,7 @@ export const IdentityVerificationOTC = ({ IdentityVerificationOTC.PreviewProps = { title: 'Confirm your identity', displayName: 'John Doe', + domain: 'example.com', oneTimeCode: 'ABC123', revocationLinkURL: 'https://auth.example.com', revocationLinkText: 'Revoke', diff --git a/internal/templates/src/index.tsx b/internal/templates/src/index.tsx index 1fc80658e..bb0db9e72 100644 --- a/internal/templates/src/index.tsx +++ b/internal/templates/src/index.tsx @@ -20,6 +20,9 @@ async function doRender() { const propsEvent = { title: "{{ .Title }}", displayName: "{{ .DisplayName }}", + bodyPrefix: "{{ .BodyPrefix }}", + bodyEvent: "{{ .BodyEvent }}", + bodySuffix: "{{ .BodySuffix }}", remoteIP: "{{ .RemoteIP }}", detailsKey: "{{ $key }}", detailsValue: "{{ index $.Details $key }}", @@ -33,6 +36,7 @@ async function doRender() { const propsJWT = { title: "{{ .Title }}", displayName: "{{ .DisplayName }}", + domain: "{{ .Domain }}", remoteIP: "{{ .RemoteIP }}", link: "{{ .LinkURL }}", linkText: "{{ .LinkText }}", @@ -46,6 +50,7 @@ async function doRender() { const propsOTC = { title: "{{ .Title }}", displayName: "{{ .DisplayName }}", + domain: "{{ .Domain }}", remoteIP: "{{ .RemoteIP }}", oneTimeCode: "{{ .OneTimeCode }}", revocationLinkURL: "{{ .RevocationLinkURL }}", diff --git a/internal/templates/types.go b/internal/templates/types.go index 1be986d74..aef9d0906 100644 --- a/internal/templates/types.go +++ b/internal/templates/types.go @@ -58,6 +58,9 @@ type EmailTemplate struct { // EmailEventValues are the values used for event templates. type EmailEventValues struct { Title string + BodyPrefix string + BodySuffix string + BodyEvent string DisplayName string Details map[string]any RemoteIP string @@ -67,6 +70,7 @@ type EmailEventValues struct { type EmailIdentityVerificationJWTValues struct { Title string DisplayName string + Domain string RemoteIP string LinkURL string LinkText string @@ -78,6 +82,7 @@ type EmailIdentityVerificationJWTValues struct { type EmailIdentityVerificationOTCValues struct { Title string DisplayName string + Domain string RemoteIP string OneTimeCode string RevocationLinkURL string |
