• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / gotrue / 8135412125

04 Mar 2024 03:34AM UTC coverage: 65.142% (+0.1%) from 65.009%
8135412125

push

github

web-flow
fix: refactor request params to use generics (#1464)

## What kind of change does this PR introduce?
* Introduce a new method `retrieveRequestParams` which makes use of
generics to parse a request
* This will help to simplify parsing a request from:
```go

params := RequestParams{}
body, err := getBodyBytes(r)
if err != nil {
  return nil, badRequestError("Could not read body").WithInternalError(err)
}

if err := json.Unmarshal(body, &params); err != nil {
  return nil, badRequestError("Could not decode request params: %v", err)
}
```
to 
```go
params := &Request{}
err := retrieveRequestParams(req, params)
```

## TODO
- [x] Add type constraint instead of using `any`

48 of 69 new or added lines in 19 files covered. (69.57%)

19 existing lines in 14 files now uncovered.

7806 of 11983 relevant lines covered (65.14%)

59.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.86
/internal/api/recover.go
1
package api
2

3
import (
4
        "errors"
5
        "net/http"
6

7
        "github.com/supabase/auth/internal/models"
8
        "github.com/supabase/auth/internal/storage"
9
        "github.com/supabase/auth/internal/utilities"
10
)
11

12
// RecoverParams holds the parameters for a password recovery request
13
type RecoverParams struct {
14
        Email               string `json:"email"`
15
        CodeChallenge       string `json:"code_challenge"`
16
        CodeChallengeMethod string `json:"code_challenge_method"`
17
}
18

19
func (p *RecoverParams) Validate() error {
8✔
20
        if p.Email == "" {
8✔
21
                return unprocessableEntityError("Password recovery requires an email")
×
22
        }
×
23
        var err error
8✔
24
        if p.Email, err = validateEmail(p.Email); err != nil {
8✔
25
                return err
×
26
        }
×
27
        if err := validatePKCEParams(p.CodeChallengeMethod, p.CodeChallenge); err != nil {
8✔
28
                return err
×
29
        }
×
30
        return nil
8✔
31
}
32

33
// Recover sends a recovery email
34
func (a *API) Recover(w http.ResponseWriter, r *http.Request) error {
8✔
35
        ctx := r.Context()
8✔
36
        db := a.db.WithContext(ctx)
8✔
37
        config := a.config
8✔
38
        params := &RecoverParams{}
8✔
39
        if err := retrieveRequestParams(r, params); err != nil {
8✔
NEW
40
                return err
×
UNCOV
41
        }
×
42

43
        flowType := getFlowFromChallenge(params.CodeChallenge)
8✔
44
        if err := params.Validate(); err != nil {
8✔
45
                return err
×
46
        }
×
47

48
        var user *models.User
8✔
49
        var err error
8✔
50
        aud := a.requestAud(ctx, r)
8✔
51

8✔
52
        user, err = models.FindUserByEmailAndAudience(db, params.Email, aud)
8✔
53
        if err != nil {
9✔
54
                if models.IsNotFoundError(err) {
2✔
55
                        return sendJSON(w, http.StatusOK, map[string]string{})
1✔
56
                }
1✔
57
                return internalServerError("Unable to process request").WithInternalError(err)
×
58
        }
59

60
        err = db.Transaction(func(tx *storage.Connection) error {
14✔
61
                if terr := models.NewAuditLogEntry(r, tx, user, models.UserRecoveryRequestedAction, "", nil); terr != nil {
7✔
62
                        return terr
×
63
                }
×
64
                mailer := a.Mailer(ctx)
7✔
65
                referrer := utilities.GetReferrer(r, config)
7✔
66
                if isPKCEFlow(flowType) {
8✔
67
                        codeChallengeMethod, terr := models.ParseCodeChallengeMethod(params.CodeChallengeMethod)
1✔
68
                        if terr != nil {
1✔
69
                                return terr
×
70
                        }
×
71
                        if terr := models.NewFlowStateWithUserID(tx, models.Recovery.String(), params.CodeChallenge, codeChallengeMethod, models.Recovery, &(user.ID)); terr != nil {
1✔
72
                                return terr
×
73
                        }
×
74
                }
75
                externalURL := getExternalHost(ctx)
7✔
76
                return a.sendPasswordRecovery(tx, user, mailer, config.SMTP.MaxFrequency, referrer, externalURL, config.Mailer.OtpLength, flowType)
7✔
77
        })
78
        if err != nil {
8✔
79
                if errors.Is(err, MaxFrequencyLimitError) {
2✔
80
                        return tooManyRequestsError("For security purposes, you can only request this once every 60 seconds")
1✔
81
                }
1✔
82
                return internalServerError("Unable to process request").WithInternalError(err)
×
83
        }
84

85
        return sendJSON(w, http.StatusOK, map[string]string{})
6✔
86
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc