@@ -48,6 +48,14 @@ func (ts *OneTimeTokenTestSuite) createUser() *User {
4848 return u
4949}
5050
51+ // seedToken starts from an empty table and returns the user who owns the row.
52+ func (ts * OneTimeTokenTestSuite ) seedToken (hash string , tokenType OneTimeTokenType ) * User {
53+ TruncateAll (ts .db )
54+ u := ts .createUser ()
55+ require .NoError (ts .T (), CreateOneTimeToken (ts .db , u .ID , u .GetEmail (), hash , tokenType , time .Minute ))
56+ return u
57+ }
58+
5159func (ts * OneTimeTokenTestSuite ) TestCreateOneTimeToken () {
5260 cases := map [string ]time.Duration {
5361 "future window" : 15 * time .Minute ,
@@ -98,11 +106,37 @@ func (ts *OneTimeTokenTestSuite) TestCreateOneTimeTokenResendReplacesWindow() {
98106 "resend must move expires_at forward, first=%s second=%s" , first .ExpiresAt , second .ExpiresAt )
99107}
100108
109+ func (ts * OneTimeTokenTestSuite ) TestFindOneTimeToken () {
110+ ts .Run ("matches the exact hash only, not the pkce_ prefixed form" , func () {
111+ ts .seedToken ("pkce_hash" , ConfirmationToken )
112+
113+ ott , err := FindOneTimeToken (ts .db , "hash" , ConfirmationToken )
114+ require .True (ts .T (), IsNotFoundError (err ), "expected not found error, got %v" , err )
115+ require .Nil (ts .T (), ott )
116+ })
117+
118+ ts .Run ("does not return a row of another token type" , func () {
119+ ts .seedToken ("hash" , RecoveryToken )
120+
121+ ott , err := FindOneTimeToken (ts .db , "hash" , ConfirmationToken )
122+ require .True (ts .T (), IsNotFoundError (err ), "expected not found error, got %v" , err )
123+ require .Nil (ts .T (), ott )
124+ })
125+
126+ ts .Run ("matches either of two token types" , func () {
127+ u := ts .seedToken ("hash" , RecoveryToken )
128+
129+ // The row has the second type, so this also checks the argument order.
130+ ott , err := FindOneTimeToken (ts .db , "hash" , ConfirmationToken , RecoveryToken )
131+ require .NoError (ts .T (), err )
132+ require .Equal (ts .T (), RecoveryToken , ott .TokenType )
133+ require .Equal (ts .T (), u .ID , ott .UserID )
134+ })
135+ }
136+
101137func (ts * OneTimeTokenTestSuite ) TestFindOneTimeTokenWithPKCEFallback () {
102138 ts .Run ("exact hash match" , func () {
103- TruncateAll (ts .db )
104- u := ts .createUser ()
105- require .NoError (ts .T (), CreateOneTimeToken (ts .db , u .ID , u .GetEmail (), "hash" , ConfirmationToken , time .Minute ))
139+ u := ts .seedToken ("hash" , ConfirmationToken )
106140
107141 ott , err := FindOneTimeTokenWithPKCEFallback (ts .db , "hash" , ConfirmationToken )
108142 require .NoError (ts .T (), err )
@@ -111,9 +145,7 @@ func (ts *OneTimeTokenTestSuite) TestFindOneTimeTokenWithPKCEFallback() {
111145 })
112146
113147 ts .Run ("falls back to pkce_ prefixed hash" , func () {
114- TruncateAll (ts .db )
115- u := ts .createUser ()
116- require .NoError (ts .T (), CreateOneTimeToken (ts .db , u .ID , u .GetEmail (), "pkce_hash" , ConfirmationToken , time .Minute ))
148+ u := ts .seedToken ("pkce_hash" , ConfirmationToken )
117149
118150 ott , err := FindOneTimeTokenWithPKCEFallback (ts .db , "hash" , ConfirmationToken )
119151 require .NoError (ts .T (), err )
@@ -122,12 +154,9 @@ func (ts *OneTimeTokenTestSuite) TestFindOneTimeTokenWithPKCEFallback() {
122154 })
123155
124156 ts .Run ("prefers exact match over pkce_ prefixed hash" , func () {
125- TruncateAll (ts .db )
126- u := ts .createUser ()
127-
128157 // (user_id, token_type) is unique, so the two candidates have to be
129158 // different types. Both types are passed so both are eligible.
130- require . NoError ( ts . T (), CreateOneTimeToken ( ts .db , u . ID , u . GetEmail (), "hash" , ConfirmationToken , time . Minute ) )
159+ u := ts .seedToken ( "hash" , ConfirmationToken )
131160 require .NoError (ts .T (), CreateOneTimeToken (ts .db , u .ID , u .GetEmail (), "pkce_hash" , RecoveryToken , time .Minute ))
132161
133162 ott , err := FindOneTimeTokenWithPKCEFallback (ts .db , "hash" , ConfirmationToken , RecoveryToken )
@@ -146,9 +175,7 @@ func (ts *OneTimeTokenTestSuite) TestFindOneTimeTokenWithPKCEFallback() {
146175 })
147176
148177 ts .Run ("token type filter applies to the pkce_ fallback" , func () {
149- TruncateAll (ts .db )
150- u := ts .createUser ()
151- require .NoError (ts .T (), CreateOneTimeToken (ts .db , u .ID , u .GetEmail (), "pkce_hash" , RecoveryToken , time .Minute ))
178+ ts .seedToken ("pkce_hash" , RecoveryToken )
152179
153180 ott , err := FindOneTimeTokenWithPKCEFallback (ts .db , "hash" , ConfirmationToken )
154181 require .True (ts .T (), IsNotFoundError (err ), "expected not found error, got %v" , err )
0 commit comments