tenseleyflow/shithub / c21cd5a

Browse files

Add 2FA notice email templates (enabled, disabled, regenerated, admin_cleared_2fa)

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
c21cd5a7e38b01b75e3673f2b47c4b92f601e342
Parents
c42837e
Tree
07923e9

1 changed file

StatusFile+-
M internal/auth/email/messages.go 87 0
internal/auth/email/messages.gomodified
@@ -65,6 +65,93 @@ password will not change.
6565
 `)))
6666
 )
6767
 
68
+// noticeBodies maps a notice kind to its (subject, plaintext, html) bodies.
69
+// Each body is run through text/template — only the canonical {{.SiteName}}
70
+// and {{.Username}} variables are exposed.
71
+var noticeBodies = map[string]struct {
72
+	Subject, Text, HTML string
73
+}{
74
+	"2fa_enabled": {
75
+		Subject: "Two-factor authentication enabled on your {{.SiteName}} account",
76
+		Text: `Hi {{.Username}},
77
+
78
+Two-factor authentication has just been enabled on your {{.SiteName}} account.
79
+If this wasn't you, sign in immediately and disable 2FA, then change your password.
80
+Recovery codes are stored on the security settings page — keep them somewhere safe.`,
81
+		HTML: `<p>Hi <strong>{{.Username}}</strong>,</p>
82
+<p>Two-factor authentication has just been enabled on your {{.SiteName}} account.</p>
83
+<p>If this wasn't you, sign in immediately and disable 2FA, then change your password.</p>
84
+<p>Recovery codes are stored on the security settings page — keep them somewhere safe.</p>`,
85
+	},
86
+	"2fa_disabled": {
87
+		Subject: "Two-factor authentication disabled on your {{.SiteName}} account",
88
+		Text: `Hi {{.Username}},
89
+
90
+Two-factor authentication has been disabled on your {{.SiteName}} account.
91
+If this wasn't you, sign in immediately and re-enable 2FA, then change your password.`,
92
+		HTML: `<p>Hi <strong>{{.Username}}</strong>,</p>
93
+<p>Two-factor authentication has been disabled on your {{.SiteName}} account.</p>
94
+<p>If this wasn't you, sign in immediately and re-enable 2FA, then change your password.</p>`,
95
+	},
96
+	"recovery_regenerated": {
97
+		Subject: "New recovery codes generated for your {{.SiteName}} account",
98
+		Text: `Hi {{.Username}},
99
+
100
+Your {{.SiteName}} recovery codes were regenerated. Any previous codes
101
+no longer work. Store the new codes somewhere safe.
102
+
103
+If this wasn't you, sign in immediately and review your security settings.`,
104
+		HTML: `<p>Hi <strong>{{.Username}}</strong>,</p>
105
+<p>Your {{.SiteName}} recovery codes were regenerated. Any previous codes no longer work. Store the new codes somewhere safe.</p>
106
+<p>If this wasn't you, sign in immediately and review your security settings.</p>`,
107
+	},
108
+	"admin_cleared_2fa": {
109
+		Subject: "Two-factor authentication cleared by support — {{.SiteName}}",
110
+		Text: `Hi {{.Username}},
111
+
112
+A {{.SiteName}} administrator cleared two-factor authentication from your
113
+account, typically as part of a support request you initiated.
114
+
115
+Sign in and re-enable 2FA at /settings/security/2fa/enable as soon as you can.
116
+
117
+If you did NOT request this, sign in immediately and reset your password,
118
+then contact support.`,
119
+		HTML: `<p>Hi <strong>{{.Username}}</strong>,</p>
120
+<p>A {{.SiteName}} administrator cleared two-factor authentication from your account, typically as part of a support request you initiated.</p>
121
+<p>Sign in and re-enable 2FA as soon as you can.</p>
122
+<p>If you did NOT request this, sign in immediately and reset your password, then contact support.</p>`,
123
+	},
124
+}
125
+
126
+// NoticeMessage builds a 2FA / security state-change notice for kind. The
127
+// kind names match audit-log Action values where applicable.
128
+func NoticeMessage(b Branding, to, username, kind string) (Message, error) {
129
+	body, ok := noticeBodies[kind]
130
+	if !ok {
131
+		return Message{}, fmt.Errorf("email: unknown notice kind %q", kind)
132
+	}
133
+	data := struct{ SiteName, Username string }{b.SiteName, username}
134
+	subj, err := renderText(textTemplate.Must(textTemplate.New("subj").Parse(body.Subject)), data)
135
+	if err != nil {
136
+		return Message{}, err
137
+	}
138
+	txt, err := renderText(textTemplate.Must(textTemplate.New("txt").Parse(body.Text)), data)
139
+	if err != nil {
140
+		return Message{}, err
141
+	}
142
+	html, err := renderHTML(template.Must(template.New("html").Parse(body.HTML)), data)
143
+	if err != nil {
144
+		return Message{}, err
145
+	}
146
+	return Message{
147
+		From:    b.From,
148
+		To:      to,
149
+		Subject: strings.TrimSpace(subj),
150
+		Text:    txt,
151
+		HTML:    html,
152
+	}, nil
153
+}
154
+
68155
 // VerifyMessage builds the email-verification message.
69156
 func VerifyMessage(b Branding, to, username, token string) (Message, error) {
70157
 	data := struct{ SiteName, BaseURL, Username, Token string }{b.SiteName, b.BaseURL, username, token}