From 126e72b6ae2331d8b6423469844e5b583cf63fcd Mon Sep 17 00:00:00 2001 From: pjpj Date: Mon, 8 Jun 2026 18:23:42 +0800 Subject: [PATCH] fix(api): reject empty email action links --- internal/api/mail.go | 3 +++ internal/api/mail_test.go | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/internal/api/mail.go b/internal/api/mail.go index 87c4841c34..3e545b845c 100644 --- a/internal/api/mail.go +++ b/internal/api/mail.go @@ -292,6 +292,9 @@ func (a *API) adminGenerateLink(w http.ResponseWriter, r *http.Request) error { if terr != nil { return terr } + if url == "" { + return apierrors.NewInternalServerError("Error generating email action link").WithInternalError(errors.New("email action link is empty")) + } return nil }) if err != nil { diff --git a/internal/api/mail_test.go b/internal/api/mail_test.go index 97ab2df892..0d575ffc2a 100644 --- a/internal/api/mail_test.go +++ b/internal/api/mail_test.go @@ -16,6 +16,7 @@ import ( "github.com/supabase/auth/internal/api/apierrors" "github.com/supabase/auth/internal/conf" "github.com/supabase/auth/internal/crypto" + mail "github.com/supabase/auth/internal/mailer" "github.com/supabase/auth/internal/models" ) @@ -249,6 +250,47 @@ func (ts *MailTestSuite) TestGenerateLink() { ts.API.config.Mailer.ExternalHosts = originalHosts } +type emptyActionLinkMailer struct { + mail.Mailer +} + +func (m emptyActionLinkMailer) GetEmailActionLink(user *models.User, actionType, referrerURL string, externalURL *url.URL) (string, error) { + return "", nil +} + +func (ts *MailTestSuite) TestGenerateLinkReturnsErrorForEmptyActionLink() { + claims := &AccessTokenClaims{ + Role: "supabase_admin", + } + token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(ts.Config.JWT.Secret)) + require.NoError(ts.T(), err, "Error generating admin jwt") + + originalMailer := ts.API.mailer + ts.API.mailer = emptyActionLinkMailer{Mailer: originalMailer} + defer func() { + ts.API.mailer = originalMailer + }() + + var buffer bytes.Buffer + require.NoError(ts.T(), json.NewEncoder(&buffer).Encode(GenerateLinkParams{ + Email: "test@example.com", + Type: "recovery", + })) + req := httptest.NewRequest(http.MethodPost, ts.Config.SiteURL+"/admin/generate_link", &buffer) + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + w := httptest.NewRecorder() + + ts.API.handler.ServeHTTP(w, req) + + require.Equal(ts.T(), http.StatusInternalServerError, w.Code) + + data := make(map[string]interface{}) + require.NoError(ts.T(), json.NewDecoder(w.Body).Decode(&data)) + require.NotContains(ts.T(), data, "action_link") + require.Equal(ts.T(), apierrors.ErrorCodeUnexpectedFailure, data["error_code"]) + require.Equal(ts.T(), "Error generating email action link", data["msg"]) +} + func (ts *MailTestSuite) setURIAllowListMap(uris ...string) { for _, uri := range uris { g := glob.MustCompile(uri, '.', '/')