()
| 66 | } |
| 67 | |
| 68 | func (ts *VerifyTestSuite) TestVerifyPasswordRecovery() { |
| 69 | // modify config so we don't hit rate limit from requesting recovery twice in 60s |
| 70 | ts.Config.SMTP.MaxFrequency = 60 |
| 71 | u, err := models.FindUserByEmailAndAudience(ts.API.db, "test@example.com", ts.Config.JWT.Aud) |
| 72 | require.NoError(ts.T(), err) |
| 73 | u.RecoverySentAt = &time.Time{} |
| 74 | require.NoError(ts.T(), ts.API.db.Update(u)) |
| 75 | testEmail := "test@example.com" |
| 76 | |
| 77 | cases := []struct { |
| 78 | desc string |
| 79 | body map[string]interface{} |
| 80 | isPKCE bool |
| 81 | }{ |
| 82 | { |
| 83 | desc: "Implict Flow Recovery", |
| 84 | body: map[string]interface{}{ |
| 85 | "email": testEmail, |
| 86 | }, |
| 87 | isPKCE: false, |
| 88 | }, |
| 89 | { |
| 90 | desc: "PKCE Flow", |
| 91 | body: map[string]interface{}{ |
| 92 | "email": testEmail, |
| 93 | // Code Challenge needs to be at least 43 characters long |
| 94 | "code_challenge": "6b151854-cc15-4e29-8db7-3d3a9f15b3066b151854-cc15-4e29-8db7-3d3a9f15b306", |
| 95 | "code_challenge_method": models.SHA256.String(), |
| 96 | }, |
| 97 | isPKCE: true, |
| 98 | }, |
| 99 | } |
| 100 | |
| 101 | for _, c := range cases { |
| 102 | ts.Run(c.desc, func() { |
| 103 | // Reset user |
| 104 | u.EmailConfirmedAt = nil |
| 105 | require.NoError(ts.T(), ts.API.db.Update(u)) |
| 106 | require.NoError(ts.T(), models.ClearAllOneTimeTokensForUser(ts.API.db, u.ID)) |
| 107 | |
| 108 | // Request body |
| 109 | var buffer bytes.Buffer |
| 110 | require.NoError(ts.T(), json.NewEncoder(&buffer).Encode(c.body)) |
| 111 | |
| 112 | // Setup request |
| 113 | req := httptest.NewRequest(http.MethodPost, "http://localhost/recover", &buffer) |
| 114 | req.Header.Set("Content-Type", "application/json") |
| 115 | |
| 116 | // Setup response recorder |
| 117 | w := httptest.NewRecorder() |
| 118 | ts.API.handler.ServeHTTP(w, req) |
| 119 | assert.Equal(ts.T(), http.StatusOK, w.Code) |
| 120 | |
| 121 | u, err = models.FindUserByEmailAndAudience(ts.API.db, "test@example.com", ts.Config.JWT.Aud) |
| 122 | require.NoError(ts.T(), err) |
| 123 | |
| 124 | assert.WithinDuration(ts.T(), time.Now(), *u.RecoverySentAt, 1*time.Second) |
| 125 | assert.False(ts.T(), u.IsConfirmed()) |
nothing calls this directly
no test coverage detected