feat: account connect
This commit is contained in:
@@ -380,6 +380,32 @@ func (r *AuthTokenRepo) FindValid(ctx context.Context, tokenHash, purpose string
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// FindValidForUser returns a non-used, non-expired token by user + hash +
|
||||
// purpose. Used by the OTP login flow where the keyspace is small (6
|
||||
// digits) — scoping by user_id prevents a global hash-collision lookup.
|
||||
func (r *AuthTokenRepo) FindValidForUser(ctx context.Context, userID, tokenHash, purpose string) (*model.AuthToken, error) {
|
||||
const q = `
|
||||
SELECT id, user_id, purpose, token_hash, expires_at, used_at, created_at
|
||||
FROM auth_tokens
|
||||
WHERE user_id = $1
|
||||
AND token_hash = $2
|
||||
AND purpose = $3
|
||||
AND used_at IS NULL
|
||||
AND expires_at > now()
|
||||
LIMIT 1`
|
||||
|
||||
t := &model.AuthToken{}
|
||||
err := r.pg.Pool.QueryRow(ctx, q, userID, tokenHash, purpose).
|
||||
Scan(&t.ID, &t.UserID, &t.Purpose, &t.TokenHash, &t.ExpiresAt, &t.UsedAt, &t.CreatedAt)
|
||||
if err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, ErrUserNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("find token: %w", err)
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// Consume marks a token as used. After this call the token can never be
|
||||
// honoured again, even if it has not yet expired.
|
||||
func (r *AuthTokenRepo) Consume(ctx context.Context, id string) error {
|
||||
|
||||
Reference in New Issue
Block a user