diff --git a/internal/api/api.go b/internal/api/api.go index edac716a6..02c3f5332 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -320,7 +320,7 @@ func (a *API) HealthCheck(w http.ResponseWriter, r *http.Request) error { } // Mailer returns NewMailer with the current tenant config -func (a *API) Mailer(ctx context.Context) mailer.Mailer { +func (a *API) Mailer() mailer.Mailer { config := a.config return mailer.NewMailer(config) } diff --git a/internal/api/external.go b/internal/api/external.go index 8fa27f4ae..8a00e3d25 100644 --- a/internal/api/external.go +++ b/internal/api/external.go @@ -382,10 +382,7 @@ func (a *API) createAccountFromExternalIdentity(tx *storage.Connection, r *http. } else { emailConfirmationSent := false if decision.CandidateEmail.Email != "" { - mailer := a.Mailer(ctx) - referrer := utilities.GetReferrer(r, config) - externalURL := getExternalHost(ctx) - if terr = sendConfirmation(tx, user, mailer, config.SMTP.MaxFrequency, referrer, externalURL, config.Mailer.OtpLength, models.ImplicitFlow); terr != nil { + if terr = a.sendConfirmation(r, tx, user, models.ImplicitFlow); terr != nil { if errors.Is(terr, MaxFrequencyLimitError) { return nil, tooManyRequestsError(ErrorCodeOverEmailSendRateLimit, "For security purposes, you can only request this once every minute") } diff --git a/internal/api/identity.go b/internal/api/identity.go index 858810f70..e3bcf3cad 100644 --- a/internal/api/identity.go +++ b/internal/api/identity.go @@ -11,7 +11,6 @@ import ( "github.com/supabase/auth/internal/api/provider" "github.com/supabase/auth/internal/models" "github.com/supabase/auth/internal/storage" - "github.com/supabase/auth/internal/utilities" ) func (a *API) DeleteIdentity(w http.ResponseWriter, r *http.Request) error { @@ -132,10 +131,7 @@ func (a *API) linkIdentityToUser(r *http.Request, ctx context.Context, tx *stora return nil, terr } if !userData.Metadata.EmailVerified { - mailer := a.Mailer(ctx) - referrer := utilities.GetReferrer(r, a.config) - externalURL := getExternalHost(ctx) - if terr := sendConfirmation(tx, targetUser, mailer, a.config.SMTP.MaxFrequency, referrer, externalURL, a.config.Mailer.OtpLength, models.ImplicitFlow); terr != nil { + if terr := a.sendConfirmation(r, tx, targetUser, models.ImplicitFlow); terr != nil { if errors.Is(terr, MaxFrequencyLimitError) { return nil, tooManyRequestsError(ErrorCodeOverSMSSendRateLimit, "For security purposes, you can only request this once every minute") } diff --git a/internal/api/invite.go b/internal/api/invite.go index 2e912b79c..2e07e7135 100644 --- a/internal/api/invite.go +++ b/internal/api/invite.go @@ -7,7 +7,6 @@ import ( "github.com/supabase/auth/internal/api/provider" "github.com/supabase/auth/internal/models" "github.com/supabase/auth/internal/storage" - "github.com/supabase/auth/internal/utilities" ) // InviteParams are the parameters the Signup endpoint accepts @@ -20,7 +19,6 @@ type InviteParams struct { func (a *API) Invite(w http.ResponseWriter, r *http.Request) error { ctx := r.Context() db := a.db.WithContext(ctx) - config := a.config adminUser := getAdminUser(ctx) params := &InviteParams{} if err := retrieveRequestParams(r, params); err != nil { @@ -81,10 +79,7 @@ func (a *API) Invite(w http.ResponseWriter, r *http.Request) error { return terr } - mailer := a.Mailer(ctx) - referrer := utilities.GetReferrer(r, config) - externalURL := getExternalHost(ctx) - if err := sendInvite(tx, user, mailer, referrer, externalURL, config.Mailer.OtpLength); err != nil { + if err := a.sendInvite(r, tx, user); err != nil { return internalServerError("Error inviting user").WithInternalError(err) } return nil diff --git a/internal/api/magic_link.go b/internal/api/magic_link.go index c0aaded7a..e197d72f6 100644 --- a/internal/api/magic_link.go +++ b/internal/api/magic_link.go @@ -12,7 +12,6 @@ import ( "github.com/sethvargo/go-password/password" "github.com/supabase/auth/internal/models" "github.com/supabase/auth/internal/storage" - "github.com/supabase/auth/internal/utilities" ) // MagicLinkParams holds the parameters for a magic link request @@ -139,10 +138,7 @@ func (a *API) MagicLink(w http.ResponseWriter, r *http.Request) error { if terr := models.NewAuditLogEntry(r, tx, user, models.UserRecoveryRequestedAction, "", nil); terr != nil { return terr } - mailer := a.Mailer(ctx) - referrer := utilities.GetReferrer(r, config) - externalURL := getExternalHost(ctx) - return a.sendMagicLink(tx, user, mailer, config.SMTP.MaxFrequency, referrer, externalURL, config.Mailer.OtpLength, flowType) + return a.sendMagicLink(r, tx, user, flowType) }) if err != nil { if errors.Is(err, MaxFrequencyLimitError) { diff --git a/internal/api/mail.go b/internal/api/mail.go index 448f5a038..db280a9c4 100644 --- a/internal/api/mail.go +++ b/internal/api/mail.go @@ -2,7 +2,6 @@ package api import ( "net/http" - "net/url" "strings" "time" @@ -11,9 +10,7 @@ import ( "github.com/pkg/errors" "github.com/sethvargo/go-password/password" "github.com/supabase/auth/internal/api/provider" - "github.com/supabase/auth/internal/conf" "github.com/supabase/auth/internal/crypto" - "github.com/supabase/auth/internal/mailer" "github.com/supabase/auth/internal/models" "github.com/supabase/auth/internal/storage" "github.com/supabase/auth/internal/utilities" @@ -45,7 +42,7 @@ func (a *API) adminGenerateLink(w http.ResponseWriter, r *http.Request) error { ctx := r.Context() db := a.db.WithContext(ctx) config := a.config - mailer := a.Mailer(ctx) + mailer := a.Mailer() adminUser := getAdminUser(ctx) params := &GenerateLinkParams{} if err := retrieveRequestParams(r, params); err != nil { @@ -263,10 +260,17 @@ func (a *API) adminGenerateLink(w http.ResponseWriter, r *http.Request) error { return sendJSON(w, http.StatusOK, resp) } -func sendConfirmation(tx *storage.Connection, u *models.User, mailer mailer.Mailer, maxFrequency time.Duration, referrerURL string, externalURL *url.URL, otpLength int, flowType models.FlowType) error { +func (a *API) sendConfirmation(r *http.Request, tx *storage.Connection, u *models.User, flowType models.FlowType) error { + ctx := r.Context() + mailer := a.Mailer() + config := a.config + otpLength := config.Mailer.OtpLength + maxFrequency := config.SMTP.MaxFrequency + referrerURL := utilities.GetReferrer(r, config) + externalURL := getExternalHost(ctx) var err error - if u.ConfirmationSentAt != nil && !u.ConfirmationSentAt.Add(maxFrequency).Before(time.Now()) { - return MaxFrequencyLimitError + if err := validateSentWithinFrequencyLimit(u.ConfirmationSentAt, maxFrequency); err != nil { + return err } oldToken := u.ConfirmationToken otp, err := crypto.GenerateOtp(otpLength) @@ -277,7 +281,7 @@ func sendConfirmation(tx *storage.Connection, u *models.User, mailer mailer.Mail token := crypto.GenerateTokenHash(u.GetEmail(), otp) u.ConfirmationToken = addFlowPrefixToToken(token, flowType) now := time.Now() - if err := mailer.ConfirmationMail(u, otp, referrerURL, externalURL); err != nil { + if err := mailer.ConfirmationMail(r, u, otp, referrerURL, externalURL); err != nil { u.ConfirmationToken = oldToken return errors.Wrap(err, "Error sending confirmation email") } @@ -290,7 +294,13 @@ func sendConfirmation(tx *storage.Connection, u *models.User, mailer mailer.Mail return nil } -func sendInvite(tx *storage.Connection, u *models.User, mailer mailer.Mailer, referrerURL string, externalURL *url.URL, otpLength int) error { +func (a *API) sendInvite(r *http.Request, tx *storage.Connection, u *models.User) error { + ctx := r.Context() + mailer := a.Mailer() + config := a.config + otpLength := config.Mailer.OtpLength + referrerURL := utilities.GetReferrer(r, config) + externalURL := getExternalHost(ctx) var err error oldToken := u.ConfirmationToken otp, err := crypto.GenerateOtp(otpLength) @@ -300,7 +310,7 @@ func sendInvite(tx *storage.Connection, u *models.User, mailer mailer.Mailer, re } u.ConfirmationToken = crypto.GenerateTokenHash(u.GetEmail(), otp) now := time.Now() - if err := mailer.InviteMail(u, otp, referrerURL, externalURL); err != nil { + if err := mailer.InviteMail(r, u, otp, referrerURL, externalURL); err != nil { u.ConfirmationToken = oldToken return errors.Wrap(err, "Error sending invite email") } @@ -314,10 +324,17 @@ func sendInvite(tx *storage.Connection, u *models.User, mailer mailer.Mailer, re return nil } -func (a *API) sendPasswordRecovery(tx *storage.Connection, u *models.User, mailer mailer.Mailer, maxFrequency time.Duration, referrerURL string, externalURL *url.URL, otpLength int, flowType models.FlowType) error { +func (a *API) sendPasswordRecovery(r *http.Request, tx *storage.Connection, u *models.User, flowType models.FlowType) error { + ctx := r.Context() + config := a.config + maxFrequency := config.SMTP.MaxFrequency + otpLength := config.Mailer.OtpLength + referrerURL := utilities.GetReferrer(r, config) + externalURL := getExternalHost(ctx) + mailer := a.Mailer() var err error - if u.RecoverySentAt != nil && !u.RecoverySentAt.Add(maxFrequency).Before(time.Now()) { - return MaxFrequencyLimitError + if err := validateSentWithinFrequencyLimit(u.RecoverySentAt, maxFrequency); err != nil { + return err } oldToken := u.RecoveryToken @@ -329,7 +346,7 @@ func (a *API) sendPasswordRecovery(tx *storage.Connection, u *models.User, maile token := crypto.GenerateTokenHash(u.GetEmail(), otp) u.RecoveryToken = addFlowPrefixToToken(token, flowType) now := time.Now() - if err := mailer.RecoveryMail(u, otp, referrerURL, externalURL); err != nil { + if err := mailer.RecoveryMail(r, u, otp, referrerURL, externalURL); err != nil { u.RecoveryToken = oldToken return errors.Wrap(err, "Error sending recovery email") } @@ -342,10 +359,15 @@ func (a *API) sendPasswordRecovery(tx *storage.Connection, u *models.User, maile return nil } -func (a *API) sendReauthenticationOtp(tx *storage.Connection, u *models.User, mailer mailer.Mailer, maxFrequency time.Duration, otpLength int) error { +func (a *API) sendReauthenticationOtp(r *http.Request, tx *storage.Connection, u *models.User) error { + config := a.config + maxFrequency := config.SMTP.MaxFrequency + otpLength := config.Mailer.OtpLength + mailer := a.Mailer() var err error - if u.ReauthenticationSentAt != nil && !u.ReauthenticationSentAt.Add(maxFrequency).Before(time.Now()) { - return MaxFrequencyLimitError + + if err := validateSentWithinFrequencyLimit(u.ReauthenticationSentAt, maxFrequency); err != nil { + return err } oldToken := u.ReauthenticationToken @@ -356,7 +378,7 @@ func (a *API) sendReauthenticationOtp(tx *storage.Connection, u *models.User, ma } u.ReauthenticationToken = crypto.GenerateTokenHash(u.GetEmail(), otp) now := time.Now() - if err := mailer.ReauthenticateMail(u, otp); err != nil { + if err := mailer.ReauthenticateMail(r, u, otp); err != nil { u.ReauthenticationToken = oldToken return errors.Wrap(err, "Error sending reauthentication email") } @@ -369,13 +391,21 @@ func (a *API) sendReauthenticationOtp(tx *storage.Connection, u *models.User, ma return nil } -func (a *API) sendMagicLink(tx *storage.Connection, u *models.User, mailer mailer.Mailer, maxFrequency time.Duration, referrerURL string, externalURL *url.URL, otpLength int, flowType models.FlowType) error { +func (a *API) sendMagicLink(r *http.Request, tx *storage.Connection, u *models.User, flowType models.FlowType) error { + ctx := r.Context() + mailer := a.Mailer() + config := a.config + otpLength := config.Mailer.OtpLength + maxFrequency := config.SMTP.MaxFrequency + referrerURL := utilities.GetReferrer(r, config) + externalURL := getExternalHost(ctx) var err error // since Magic Link is just a recovery with a different template and behaviour // around new users we will reuse the recovery db timer to prevent potential abuse - if u.RecoverySentAt != nil && !u.RecoverySentAt.Add(maxFrequency).Before(time.Now()) { - return MaxFrequencyLimitError + if err := validateSentWithinFrequencyLimit(u.RecoverySentAt, maxFrequency); err != nil { + return err } + oldToken := u.RecoveryToken otp, err := crypto.GenerateOtp(otpLength) if err != nil { @@ -386,7 +416,7 @@ func (a *API) sendMagicLink(tx *storage.Connection, u *models.User, mailer maile u.RecoveryToken = addFlowPrefixToToken(token, flowType) now := time.Now() - if err := mailer.MagicLinkMail(u, otp, referrerURL, externalURL); err != nil { + if err := mailer.MagicLinkMail(r, u, otp, referrerURL, externalURL); err != nil { u.RecoveryToken = oldToken return errors.Wrap(err, "Error sending magic link email") } @@ -400,11 +430,18 @@ func (a *API) sendMagicLink(tx *storage.Connection, u *models.User, mailer maile } // sendEmailChange sends out an email change token to the new email. -func (a *API) sendEmailChange(tx *storage.Connection, config *conf.GlobalConfiguration, u *models.User, mailer mailer.Mailer, email, referrerURL string, externalURL *url.URL, otpLength int, flowType models.FlowType) error { +func (a *API) sendEmailChange(r *http.Request, tx *storage.Connection, u *models.User, email string, flowType models.FlowType) error { + ctx := r.Context() + config := a.config + otpLength := config.Mailer.OtpLength var err error - if u.EmailChangeSentAt != nil && !u.EmailChangeSentAt.Add(config.SMTP.MaxFrequency).Before(time.Now()) { - return MaxFrequencyLimitError + mailer := a.Mailer() + if err := validateSentWithinFrequencyLimit(u.EmailChangeSentAt, config.SMTP.MaxFrequency); err != nil { + return err } + referrerURL := utilities.GetReferrer(r, config) + externalURL := getExternalHost(ctx) + otpNew, err := crypto.GenerateOtp(otpLength) if err != nil { // OTP generation must succeed @@ -427,7 +464,7 @@ func (a *API) sendEmailChange(tx *storage.Connection, config *conf.GlobalConfigu u.EmailChangeConfirmStatus = zeroConfirmation now := time.Now() - if err := mailer.EmailChangeMail(u, otpNew, otpCurrent, referrerURL, externalURL); err != nil { + if err := mailer.EmailChangeMail(r, u, otpNew, otpCurrent, referrerURL, externalURL); err != nil { return err } @@ -457,3 +494,10 @@ func validateEmail(email string) (string, error) { } return strings.ToLower(email), nil } + +func validateSentWithinFrequencyLimit(sentAt *time.Time, frequency time.Duration) error { + if sentAt != nil && sentAt.Add(frequency).After(time.Now()) { + return MaxFrequencyLimitError + } + return nil +} diff --git a/internal/api/reauthenticate.go b/internal/api/reauthenticate.go index 84b080070..54ee8f775 100644 --- a/internal/api/reauthenticate.go +++ b/internal/api/reauthenticate.go @@ -42,8 +42,7 @@ func (a *API) Reauthenticate(w http.ResponseWriter, r *http.Request) error { return terr } if email != "" { - mailer := a.Mailer(ctx) - return a.sendReauthenticationOtp(tx, user, mailer, config.SMTP.MaxFrequency, config.Mailer.OtpLength) + return a.sendReauthenticationOtp(r, tx, user) } else if phone != "" { smsProvider, terr := sms_provider.GetSmsProvider(*config) if terr != nil { diff --git a/internal/api/recover.go b/internal/api/recover.go index a3201852d..0fa9760ae 100644 --- a/internal/api/recover.go +++ b/internal/api/recover.go @@ -6,7 +6,6 @@ import ( "github.com/supabase/auth/internal/models" "github.com/supabase/auth/internal/storage" - "github.com/supabase/auth/internal/utilities" ) // RecoverParams holds the parameters for a password recovery request @@ -34,7 +33,6 @@ func (p *RecoverParams) Validate() error { func (a *API) Recover(w http.ResponseWriter, r *http.Request) error { ctx := r.Context() db := a.db.WithContext(ctx) - config := a.config params := &RecoverParams{} if err := retrieveRequestParams(r, params); err != nil { return err @@ -66,10 +64,7 @@ func (a *API) Recover(w http.ResponseWriter, r *http.Request) error { if terr := models.NewAuditLogEntry(r, tx, user, models.UserRecoveryRequestedAction, "", nil); terr != nil { return terr } - mailer := a.Mailer(ctx) - referrer := utilities.GetReferrer(r, config) - externalURL := getExternalHost(ctx) - return a.sendPasswordRecovery(tx, user, mailer, config.SMTP.MaxFrequency, referrer, externalURL, config.Mailer.OtpLength, flowType) + return a.sendPasswordRecovery(r, tx, user, flowType) }) if err != nil { if errors.Is(err, MaxFrequencyLimitError) { diff --git a/internal/api/resend.go b/internal/api/resend.go index fdad38c43..7b9297a69 100644 --- a/internal/api/resend.go +++ b/internal/api/resend.go @@ -9,7 +9,6 @@ import ( "github.com/supabase/auth/internal/conf" "github.com/supabase/auth/internal/models" "github.com/supabase/auth/internal/storage" - "github.com/supabase/auth/internal/utilities" ) // ResendConfirmationParams holds the parameters for a resend request @@ -115,9 +114,6 @@ func (a *API) Resend(w http.ResponseWriter, r *http.Request) error { } messageID := "" - mailer := a.Mailer(ctx) - referrer := utilities.GetReferrer(r, config) - externalURL := getExternalHost(ctx) err = db.Transaction(func(tx *storage.Connection) error { switch params.Type { case signupVerification: @@ -125,7 +121,7 @@ func (a *API) Resend(w http.ResponseWriter, r *http.Request) error { return terr } // PKCE not implemented yet - return sendConfirmation(tx, user, mailer, config.SMTP.MaxFrequency, referrer, externalURL, config.Mailer.OtpLength, models.ImplicitFlow) + return a.sendConfirmation(r, tx, user, models.ImplicitFlow) case smsVerification: if terr := models.NewAuditLogEntry(r, tx, user, models.UserRecoveryRequestedAction, "", nil); terr != nil { return terr @@ -140,7 +136,7 @@ func (a *API) Resend(w http.ResponseWriter, r *http.Request) error { } messageID = mID case emailChangeVerification: - return a.sendEmailChange(tx, config, user, mailer, user.EmailChange, referrer, externalURL, config.Mailer.OtpLength, models.ImplicitFlow) + return a.sendEmailChange(r, tx, user, user.EmailChange, models.ImplicitFlow) case phoneChangeVerification: smsProvider, terr := sms_provider.GetSmsProvider(*config) if terr != nil { diff --git a/internal/api/signup.go b/internal/api/signup.go index a17323687..91c14ef7c 100644 --- a/internal/api/signup.go +++ b/internal/api/signup.go @@ -14,7 +14,6 @@ import ( "github.com/supabase/auth/internal/metering" "github.com/supabase/auth/internal/models" "github.com/supabase/auth/internal/storage" - "github.com/supabase/auth/internal/utilities" ) // SignupParams are the parameters the Signup endpoint accepts @@ -234,8 +233,6 @@ func (a *API) Signup(w http.ResponseWriter, r *http.Request) error { return internalServerError("Database error updating user").WithInternalError(terr) } } else { - mailer := a.Mailer(ctx) - referrer := utilities.GetReferrer(r, config) if terr = models.NewAuditLogEntry(r, tx, user, models.UserConfirmationRequestedAction, "", map[string]interface{}{ "provider": params.Provider, }); terr != nil { @@ -247,8 +244,7 @@ func (a *API) Signup(w http.ResponseWriter, r *http.Request) error { return terr } } - externalURL := getExternalHost(ctx) - if terr = sendConfirmation(tx, user, mailer, config.SMTP.MaxFrequency, referrer, externalURL, config.Mailer.OtpLength, flowType); terr != nil { + if terr = a.sendConfirmation(r, tx, user, flowType); terr != nil { if errors.Is(terr, MaxFrequencyLimitError) { now := time.Now() left := user.ConfirmationSentAt.Add(config.SMTP.MaxFrequency).Sub(now) / time.Second diff --git a/internal/api/user.go b/internal/api/user.go index 9fe0dcef8..43b2e9de8 100644 --- a/internal/api/user.go +++ b/internal/api/user.go @@ -10,7 +10,6 @@ import ( "github.com/supabase/auth/internal/api/sms_provider" "github.com/supabase/auth/internal/models" "github.com/supabase/auth/internal/storage" - "github.com/supabase/auth/internal/utilities" ) // UserUpdateParams parameters for updating a user @@ -194,8 +193,6 @@ func (a *API) UserUpdate(w http.ResponseWriter, r *http.Request) error { } if params.Email != "" && params.Email != user.GetEmail() { - mailer := a.Mailer(ctx) - referrer := utilities.GetReferrer(r, config) flowType := getFlowFromChallenge(params.CodeChallenge) if isPKCEFlow(flowType) { _, terr := generateFlowState(tx, models.EmailChange.String(), models.EmailChange, params.CodeChallengeMethod, params.CodeChallenge, &user.ID) @@ -204,8 +201,7 @@ func (a *API) UserUpdate(w http.ResponseWriter, r *http.Request) error { } } - externalURL := getExternalHost(ctx) - if terr = a.sendEmailChange(tx, config, user, mailer, params.Email, referrer, externalURL, config.Mailer.OtpLength, flowType); terr != nil { + if terr = a.sendEmailChange(r, tx, user, params.Email, flowType); terr != nil { if errors.Is(terr, MaxFrequencyLimitError) { return tooManyRequestsError(ErrorCodeOverEmailSendRateLimit, "For security purposes, you can only request this once every 60 seconds") } diff --git a/internal/mailer/mailer.go b/internal/mailer/mailer.go index 702bbd7e3..34460c744 100644 --- a/internal/mailer/mailer.go +++ b/internal/mailer/mailer.go @@ -2,6 +2,7 @@ package mailer import ( "fmt" + "net/http" "net/url" "github.com/gofrs/uuid" @@ -15,12 +16,12 @@ import ( // Mailer defines the interface a mailer must implement. type Mailer interface { Send(user *models.User, subject, body string, data map[string]interface{}) error - InviteMail(user *models.User, otp, referrerURL string, externalURL *url.URL) error - ConfirmationMail(user *models.User, otp, referrerURL string, externalURL *url.URL) error - RecoveryMail(user *models.User, otp, referrerURL string, externalURL *url.URL) error - MagicLinkMail(user *models.User, otp, referrerURL string, externalURL *url.URL) error - EmailChangeMail(user *models.User, otpNew, otpCurrent, referrerURL string, externalURL *url.URL) error - ReauthenticateMail(user *models.User, otp string) error + InviteMail(r *http.Request, user *models.User, otp, referrerURL string, externalURL *url.URL) error + ConfirmationMail(r *http.Request, user *models.User, otp, referrerURL string, externalURL *url.URL) error + RecoveryMail(r *http.Request, user *models.User, otp, referrerURL string, externalURL *url.URL) error + MagicLinkMail(r *http.Request, user *models.User, otp, referrerURL string, externalURL *url.URL) error + EmailChangeMail(r *http.Request, user *models.User, otpNew, otpCurrent, referrerURL string, externalURL *url.URL) error + ReauthenticateMail(r *http.Request, user *models.User, otp string) error ValidateEmail(email string) error GetEmailActionLink(user *models.User, actionType, referrerURL string, externalURL *url.URL) (string, error) } diff --git a/internal/mailer/template.go b/internal/mailer/template.go index ba6c22335..9ecc749f1 100644 --- a/internal/mailer/template.go +++ b/internal/mailer/template.go @@ -2,6 +2,7 @@ package mailer import ( "fmt" + "net/http" "net/url" "strings" @@ -75,7 +76,7 @@ func (m TemplateMailer) ValidateEmail(email string) error { } // InviteMail sends a invite mail to a new user -func (m *TemplateMailer) InviteMail(user *models.User, otp, referrerURL string, externalURL *url.URL) error { +func (m *TemplateMailer) InviteMail(r *http.Request, user *models.User, otp, referrerURL string, externalURL *url.URL) error { path, err := getPath(m.Config.Mailer.URLPaths.Invite, &EmailParams{ Token: user.ConfirmationToken, Type: "invite", @@ -106,7 +107,7 @@ func (m *TemplateMailer) InviteMail(user *models.User, otp, referrerURL string, } // ConfirmationMail sends a signup confirmation mail to a new user -func (m *TemplateMailer) ConfirmationMail(user *models.User, otp, referrerURL string, externalURL *url.URL) error { +func (m *TemplateMailer) ConfirmationMail(r *http.Request, user *models.User, otp, referrerURL string, externalURL *url.URL) error { path, err := getPath(m.Config.Mailer.URLPaths.Confirmation, &EmailParams{ Token: user.ConfirmationToken, Type: "signup", @@ -136,7 +137,7 @@ func (m *TemplateMailer) ConfirmationMail(user *models.User, otp, referrerURL st } // ReauthenticateMail sends a reauthentication mail to an authenticated user -func (m *TemplateMailer) ReauthenticateMail(user *models.User, otp string) error { +func (m *TemplateMailer) ReauthenticateMail(r *http.Request, user *models.User, otp string) error { data := map[string]interface{}{ "SiteURL": m.Config.SiteURL, "Email": user.Email, @@ -154,7 +155,7 @@ func (m *TemplateMailer) ReauthenticateMail(user *models.User, otp string) error } // EmailChangeMail sends an email change confirmation mail to a user -func (m *TemplateMailer) EmailChangeMail(user *models.User, otpNew, otpCurrent, referrerURL string, externalURL *url.URL) error { +func (m *TemplateMailer) EmailChangeMail(r *http.Request, user *models.User, otpNew, otpCurrent, referrerURL string, externalURL *url.URL) error { type Email struct { Address string Otp string @@ -229,7 +230,7 @@ func (m *TemplateMailer) EmailChangeMail(user *models.User, otpNew, otpCurrent, } // RecoveryMail sends a password recovery mail -func (m *TemplateMailer) RecoveryMail(user *models.User, otp, referrerURL string, externalURL *url.URL) error { +func (m *TemplateMailer) RecoveryMail(r *http.Request, user *models.User, otp, referrerURL string, externalURL *url.URL) error { path, err := getPath(m.Config.Mailer.URLPaths.Recovery, &EmailParams{ Token: user.RecoveryToken, Type: "recovery", @@ -258,7 +259,7 @@ func (m *TemplateMailer) RecoveryMail(user *models.User, otp, referrerURL string } // MagicLinkMail sends a login link mail -func (m *TemplateMailer) MagicLinkMail(user *models.User, otp, referrerURL string, externalURL *url.URL) error { +func (m *TemplateMailer) MagicLinkMail(r *http.Request, user *models.User, otp, referrerURL string, externalURL *url.URL) error { path, err := getPath(m.Config.Mailer.URLPaths.Recovery, &EmailParams{ Token: user.RecoveryToken, Type: "magiclink",