Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: maintain query params order #1161

Merged
merged 3 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions internal/mailer/mailer.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ type Mailer interface {
GetEmailActionLink(user *models.User, actionType, referrerURL string, externalURL *url.URL) (string, error)
}

type EmailParams struct {
Token string
Type string
RedirectTo string
}

// NewMailer returns a new gotrue mailer
func NewMailer(globalConfig *conf.GlobalConfiguration) Mailer {
mail := gomail.NewMessage()
Expand Down Expand Up @@ -64,7 +70,7 @@ func withDefault(value, defaultValue string) string {
return value
}

func getPath(filepath string, params map[string]string) (*url.URL, error) {
func getPath(filepath string, params *EmailParams) (*url.URL, error) {
path := &url.URL{}
if filepath != "" {
if p, err := url.Parse(filepath); err != nil {
Expand All @@ -73,11 +79,8 @@ func getPath(filepath string, params map[string]string) (*url.URL, error) {
path = p
}
}
v := url.Values{}
for key, val := range params {
v.Add(key, val)
if params != nil {
path.RawQuery = fmt.Sprintf("token=%s&type=%s&redirect_to=%s", params.Token, params.Type, params.RedirectTo)
kangmingtay marked this conversation as resolved.
Show resolved Hide resolved
}
// this should never return an error because we're always encoding the values first
path.RawQuery, _ = url.QueryUnescape(v.Encode())
return path, nil
}
36 changes: 14 additions & 22 deletions internal/mailer/mailer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@ func enforceRelativeURL(url string) string {
}

func TestGetPath(t *testing.T) {
params := EmailParams{
Token: "token",
Type: "signup",
RedirectTo: "https://example.com",
}
cases := []struct {
SiteURL string
Path string
Params map[string]string
Params *EmailParams
Expected string
}{
{
Expand All @@ -40,29 +45,16 @@ func TestGetPath(t *testing.T) {
Expected: "https://test.example.com/trailingslash/",
},
{
SiteURL: "https://test.example.com",
Path: "f",
Params: map[string]string{
"key": "val",
},
Expected: "https://test.example.com/f?key=val",
},
{
SiteURL: "https://test.example.com",
Path: "",
Params: map[string]string{
"key": "val",
},
Expected: "https://test.example.com?key=val",
SiteURL: "https://test.example.com",
Path: "f",
Params: &params,
Expected: "https://test.example.com/f?token=token&type=signup&redirect_to=https://example.com",
},
{
SiteURL: "https://test.example.com",
Path: "",
Params: map[string]string{
"key": "val",
"redirect_to": "http://localhost:3000?param=foo",
},
Expected: "https://test.example.com?key=val&redirect_to=http://localhost:3000?param=foo",
SiteURL: "https://test.example.com",
Path: "",
Params: &params,
Expected: "https://test.example.com?token=token&type=signup&redirect_to=https://example.com",
},
}

Expand Down
88 changes: 44 additions & 44 deletions internal/mailer/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ 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 {
path, err := getPath(m.Config.Mailer.URLPaths.Invite, map[string]string{
"token": user.ConfirmationToken,
"type": "invite",
"redirect_to": encodeRedirectURL(referrerURL),
path, err := getPath(m.Config.Mailer.URLPaths.Invite, &EmailParams{
Token: user.ConfirmationToken,
Type: "invite",
RedirectTo: encodeRedirectURL(referrerURL),
})

if err != nil {
Expand All @@ -106,10 +106,10 @@ 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 {
path, err := getPath(m.Config.Mailer.URLPaths.Confirmation, map[string]string{
"token": user.ConfirmationToken,
"type": "signup",
"redirect_to": encodeRedirectURL(referrerURL),
path, err := getPath(m.Config.Mailer.URLPaths.Confirmation, &EmailParams{
Token: user.ConfirmationToken,
Type: "signup",
RedirectTo: encodeRedirectURL(referrerURL),
})
if err != nil {
return err
Expand Down Expand Up @@ -185,10 +185,10 @@ func (m *TemplateMailer) EmailChangeMail(user *models.User, otpNew, otpCurrent,
for _, email := range emails {
path, err := getPath(
m.Config.Mailer.URLPaths.EmailChange,
map[string]string{
"token": email.TokenHash,
"type": "email_change",
"redirect_to": encodeRedirectURL(referrerURL),
&EmailParams{
Token: email.TokenHash,
Type: "email_change",
RedirectTo: encodeRedirectURL(referrerURL),
},
)
if err != nil {
Expand Down Expand Up @@ -226,10 +226,10 @@ 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 {
path, err := getPath(m.Config.Mailer.URLPaths.Recovery, map[string]string{
"token": user.RecoveryToken,
"type": "recovery",
"redirect_to": encodeRedirectURL(referrerURL),
path, err := getPath(m.Config.Mailer.URLPaths.Recovery, &EmailParams{
Token: user.RecoveryToken,
Type: "recovery",
RedirectTo: encodeRedirectURL(referrerURL),
})
if err != nil {
return err
Expand All @@ -254,10 +254,10 @@ 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 {
path, err := getPath(m.Config.Mailer.URLPaths.Recovery, map[string]string{
"token": user.RecoveryToken,
"type": "magiclink",
"redirect_to": encodeRedirectURL(referrerURL),
path, err := getPath(m.Config.Mailer.URLPaths.Recovery, &EmailParams{
Token: user.RecoveryToken,
Type: "magiclink",
RedirectTo: encodeRedirectURL(referrerURL),
})
if err != nil {
return err
Expand Down Expand Up @@ -300,40 +300,40 @@ func (m TemplateMailer) GetEmailActionLink(user *models.User, actionType, referr
referrerURL = encodeRedirectURL(referrerURL)
switch actionType {
case "magiclink":
path, err = getPath(m.Config.Mailer.URLPaths.Recovery, map[string]string{
"token": user.RecoveryToken,
"type": "magiclink",
"redirect_to": referrerURL,
path, err = getPath(m.Config.Mailer.URLPaths.Recovery, &EmailParams{
Token: user.RecoveryToken,
Type: "magiclink",
RedirectTo: referrerURL,
})
case "recovery":
path, err = getPath(m.Config.Mailer.URLPaths.Recovery, map[string]string{
"token": user.RecoveryToken,
"type": "recovery",
"redirect_to": referrerURL,
path, err = getPath(m.Config.Mailer.URLPaths.Recovery, &EmailParams{
Token: user.RecoveryToken,
Type: "recovery",
RedirectTo: referrerURL,
})
case "invite":
path, err = getPath(m.Config.Mailer.URLPaths.Invite, map[string]string{
"token": user.ConfirmationToken,
"type": "invite",
"redirect_to": referrerURL,
path, err = getPath(m.Config.Mailer.URLPaths.Invite, &EmailParams{
Token: user.ConfirmationToken,
Type: "invite",
RedirectTo: referrerURL,
})
case "signup":
path, err = getPath(m.Config.Mailer.URLPaths.Confirmation, map[string]string{
"token": user.ConfirmationToken,
"type": "signup",
"redirect_to": referrerURL,
path, err = getPath(m.Config.Mailer.URLPaths.Confirmation, &EmailParams{
Token: user.ConfirmationToken,
Type: "signup",
RedirectTo: referrerURL,
})
case "email_change_current":
path, err = getPath(m.Config.Mailer.URLPaths.EmailChange, map[string]string{
"token": user.EmailChangeTokenCurrent,
"type": "email_change",
"redirect_to": referrerURL,
path, err = getPath(m.Config.Mailer.URLPaths.EmailChange, &EmailParams{
Token: user.EmailChangeTokenCurrent,
Type: "email_change",
RedirectTo: referrerURL,
})
case "email_change_new":
path, err = getPath(m.Config.Mailer.URLPaths.EmailChange, map[string]string{
"token": user.EmailChangeTokenNew,
"type": "email_change",
"redirect_to": referrerURL,
path, err = getPath(m.Config.Mailer.URLPaths.EmailChange, &EmailParams{
Token: user.EmailChangeTokenNew,
Type: "email_change",
RedirectTo: referrerURL,
})
default:
return "", fmt.Errorf("invalid email action link type: %s", actionType)
Expand Down