Fix verification attempts not transactional (#2549)
* Run verification token check in one transaction * Only fetch unexpired verification requests
This commit is contained in:
parent
919e71de79
commit
06872a1314
@ -327,38 +327,43 @@ export const getAuthOptions = (req, res) => ({
|
||||
return user
|
||||
},
|
||||
useVerificationToken: async ({ identifier, token }) => {
|
||||
// we need to find the most recent verification request for this email/identifier
|
||||
const verificationRequest = await prisma.verificationToken.findFirst({
|
||||
where: {
|
||||
identifier,
|
||||
attempts: {
|
||||
lt: 2 // count starts at 0
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: 'desc'
|
||||
return await prisma.$transaction(async (tx) => {
|
||||
const [verificationRequest] = await tx.$queryRaw`
|
||||
UPDATE verification_requests
|
||||
SET attempts = attempts + 1
|
||||
FROM (
|
||||
SELECT id FROM verification_requests
|
||||
WHERE identifier = ${identifier}
|
||||
AND created_at > NOW() - INTERVAL '5 minutes'
|
||||
-- we need to find the most recent verification request for this email/identifier
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
FOR UPDATE
|
||||
) for_update
|
||||
WHERE verification_requests.id = for_update.id
|
||||
RETURNING *
|
||||
`
|
||||
if (!verificationRequest) throw new Error('No verification request found')
|
||||
|
||||
if (verificationRequest.token === token) {
|
||||
// correct token was entered, delete the verification request because we no longer need it
|
||||
await tx.verificationToken.delete({
|
||||
where: { id: verificationRequest.id }
|
||||
})
|
||||
return verificationRequest
|
||||
}
|
||||
|
||||
if (verificationRequest.attempts >= 3) {
|
||||
// too many attempts, delete the verification request and redirect to error page by throwing an error
|
||||
await tx.verificationToken.delete({
|
||||
where: { id: verificationRequest.id }
|
||||
})
|
||||
throw new Error('too many attempts')
|
||||
}
|
||||
|
||||
// wrong code but can try again
|
||||
return null
|
||||
})
|
||||
|
||||
if (!verificationRequest) throw new Error('No verification request found')
|
||||
|
||||
if (verificationRequest.token === token) { // if correct delete the token and continue
|
||||
await prisma.verificationToken.delete({
|
||||
where: { id: verificationRequest.id }
|
||||
})
|
||||
return verificationRequest
|
||||
}
|
||||
|
||||
await prisma.verificationToken.update({
|
||||
where: { id: verificationRequest.id },
|
||||
data: { attempts: { increment: 1 } }
|
||||
})
|
||||
|
||||
await prisma.verificationToken.deleteMany({
|
||||
where: { id: verificationRequest.id, attempts: { gte: 2 } }
|
||||
})
|
||||
|
||||
return null
|
||||
}
|
||||
},
|
||||
session: {
|
||||
|
Loading…
x
Reference in New Issue
Block a user