diff --git a/models/unittest/unit_tests.go b/models/unittest/unit_tests.go index 75898436f..00c7dd845 100644 --- a/models/unittest/unit_tests.go +++ b/models/unittest/unit_tests.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "xorm.io/builder" ) @@ -130,6 +131,12 @@ func AssertSuccessfulInsert(t assert.TestingT, beans ...any) { assert.NoError(t, err) } +// AssertSuccessfulDelete assert that beans is successfully deleted +func AssertSuccessfulDelete(t require.TestingT, beans ...any) { + err := db.DeleteBeans(db.DefaultContext, beans...) + require.NoError(t, err) +} + // AssertCount assert the count of a bean func AssertCount(t assert.TestingT, bean, expected any) bool { return assert.EqualValues(t, expected, GetCount(t, bean)) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4720207a6..5bca75a1b 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -517,6 +517,10 @@ removed_security_key.no_2fa = There are no other 2FA methods configured anymore, account_security_caution.text_1 = If this was you, then you can safely ignore this mail. account_security_caution.text_2 = If this wasn't you, your account is compromised. Please contact the admins of this site. +totp_enrolled.subject = You have activated TOTP as 2FA method +totp_enrolled.text_1.no_webauthn = You have just enabled TOTP for your account. This means that for all future logins to your account, you must use TOTP as a 2FA method. +totp_enrolled.text_1.has_webauthn = You have just enabled TOTP for your account. This means that for all future logins to your account, you could use TOTP as a 2FA method or use any of your security keys. + register_success = Registration successful issue_assigned.pull = @%[1]s assigned you to pull request %[2]s in repository %[3]s. diff --git a/routers/web/user/setting/security/2fa.go b/routers/web/user/setting/security/2fa.go index 1b1d385af..a145867ea 100644 --- a/routers/web/user/setting/security/2fa.go +++ b/routers/web/user/setting/security/2fa.go @@ -243,6 +243,11 @@ func EnrollTwoFactorPost(ctx *context.Context) { log.Error("Unable to save changes to the session: %v", err) } + if err := mailer.SendTOTPEnrolled(ctx, ctx.Doer); err != nil { + ctx.ServerError("SendTOTPEnrolled", err) + return + } + if err = auth.NewTwoFactor(ctx, t); err != nil { // FIXME: We need to handle a unique constraint fail here it's entirely possible that another request has beaten us. // If there is a unique constraint fail we should just tolerate the error diff --git a/services/mailer/mail.go b/services/mailer/mail.go index 87df3d139..01ab84bcf 100644 --- a/services/mailer/mail.go +++ b/services/mailer/mail.go @@ -44,6 +44,7 @@ const ( mailAuthPrimaryMailChange base.TplName = "auth/primary_mail_change" mailAuth2faDisabled base.TplName = "auth/2fa_disabled" mailAuthRemovedSecurityKey base.TplName = "auth/removed_security_key" + mailAuthTOTPEnrolled base.TplName = "auth/totp_enrolled" mailNotifyCollaborator base.TplName = "notify/collaborator" @@ -696,3 +697,36 @@ func SendRemovedSecurityKey(ctx context.Context, u *user_model.User, securityKey SendAsync(msg) return nil } + +// SendTOTPEnrolled informs the user that they've been enrolled into TOTP. +func SendTOTPEnrolled(ctx context.Context, u *user_model.User) error { + if setting.MailService == nil { + return nil + } + locale := translation.NewLocale(u.Language) + + hasWebAuthn, err := auth_model.HasWebAuthnRegistrationsByUID(ctx, u.ID) + if err != nil { + return err + } + + data := map[string]any{ + "locale": locale, + "HasWebAuthn": hasWebAuthn, + "DisplayName": u.DisplayName(), + "Username": u.Name, + "Language": locale.Language(), + } + + var content bytes.Buffer + + if err := bodyTemplates.ExecuteTemplate(&content, string(mailAuthTOTPEnrolled), data); err != nil { + return err + } + + msg := NewMessage(u.EmailTo(), locale.TrString("mail.totp_enrolled.subject"), content.String()) + msg.Info = fmt.Sprintf("UID: %d, enrolled into TOTP notification", u.ID) + + SendAsync(msg) + return nil +} diff --git a/templates/mail/auth/totp_enrolled.tmpl b/templates/mail/auth/totp_enrolled.tmpl new file mode 100644 index 000000000..9c665e028 --- /dev/null +++ b/templates/mail/auth/totp_enrolled.tmpl @@ -0,0 +1,15 @@ + + +
+ + + + + +{{.locale.Tr "mail.hi_user_x" (.DisplayName|DotEscape)}}
{{.locale.Tr "mail.totp_enrolled.text_1.has_webauthn"}}
{{else}}{{.locale.Tr "mail.totp_enrolled.text_1.no_webauthn"}}
{{end}}{{.locale.Tr "mail.account_security_caution.text_1"}}
{{.locale.Tr "mail.account_security_caution.text_2"}}