-
Notifications
You must be signed in to change notification settings - Fork 1
lock otp db row #99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
lock otp db row #99
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -252,14 +252,29 @@ export class WithdrawalService { | |
| ); | ||
| return { error: otpError }; | ||
| } else { | ||
| const otpResponse = await this.otpService.verifyOtpCode( | ||
| otpCode, | ||
| userInfo, | ||
| reference_type.WITHDRAW_PAYMENT, | ||
| ); | ||
| try { | ||
| const otpResponse = await this.otpService.verifyOtpCode( | ||
| otpCode, | ||
| userInfo, | ||
| reference_type.WITHDRAW_PAYMENT, | ||
| ); | ||
|
|
||
| if (!otpResponse || otpResponse.code !== 'success') { | ||
| return { error: otpResponse }; | ||
| if (!otpResponse || otpResponse.code !== 'success') { | ||
| return { error: otpResponse }; | ||
| } | ||
| } catch (error) { | ||
| if (error.code === 'P2010' && error.meta?.code === '55P03') { | ||
| this.logger.error( | ||
| 'Payment request denied because payment row was locked previously!', | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| error, | ||
| ); | ||
|
|
||
| throw new Error( | ||
| 'Some or all of the winnings you requested to process are either processing, on hold or already paid.', | ||
| ); | ||
| } else { | ||
| throw error; | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| import { Injectable, Logger } from '@nestjs/common'; | ||
| import { PrismaService } from './prisma.service'; | ||
| import crypto from 'crypto'; | ||
| import { reference_type } from '@prisma/client'; | ||
| import { otp, reference_type } from '@prisma/client'; | ||
| import { ENV_CONFIG } from 'src/config'; | ||
| import { TopcoderEmailService } from '../topcoder/tc-email.service'; | ||
| import { BasicMemberInfo } from '../topcoder'; | ||
|
|
@@ -104,62 +104,65 @@ export class OtpService { | |
| userInfo: BasicMemberInfo, | ||
| actionType: reference_type, | ||
| ) { | ||
| const record = await this.prisma.otp.findFirst({ | ||
| where: { | ||
| otp_hash: hashOtp(otpCode), | ||
| }, | ||
| orderBy: { | ||
| expiration_time: 'desc', | ||
| }, | ||
| }); | ||
|
|
||
| if (!record) { | ||
| this.logger.warn(`No OTP record found for the provided code.`); | ||
| return { code: 'otp_invalid', message: `Invalid OTP code.` }; | ||
| } | ||
|
|
||
| if (record.email !== userInfo.email) { | ||
| this.logger.warn(`Email mismatch for OTP verification.`); | ||
| return { | ||
| code: 'otp_email_mismatch', | ||
| message: `Email mismatch for OTP verification.`, | ||
| }; | ||
| } | ||
|
|
||
| if (record.action_type !== actionType) { | ||
| this.logger.warn(`Action type mismatch for OTP verification.`); | ||
| return { | ||
| code: 'otp_action_type_mismatch', | ||
| message: `Action type mismatch for OTP verification.`, | ||
| }; | ||
| } | ||
|
|
||
| if (record.expiration_time && record.expiration_time < new Date()) { | ||
| this.logger.warn(`OTP code has expired.`); | ||
| return { code: 'otp_expired', message: `OTP code has expired.` }; | ||
| } | ||
|
|
||
| if (record.verified_at !== null) { | ||
| this.logger.warn(`OTP code has already been verified.`); | ||
| return { | ||
| code: 'otp_already_verified', | ||
| message: `OTP code has already been verified.`, | ||
| }; | ||
| } | ||
| return await this.prisma.$transaction(async (tx) => { | ||
| const records = await tx.$queryRaw<otp>` | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [❗❗ |
||
| SELECT id, email, otp_hash, expiration_time, action_type, created_at, updated_at, verified_at | ||
| FROM otp | ||
| WHERE otp_hash=${hashOtp(otpCode)} | ||
| ORDER BY expiration_time DESC | ||
| LIMIT 1 | ||
| FOR UPDATE NOWAIT; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [ |
||
| `; | ||
| const record = records[0]; | ||
|
|
||
| if (!record) { | ||
| this.logger.warn(`No OTP record found for the provided code.`); | ||
| return { code: 'otp_invalid', message: `Invalid OTP code.` }; | ||
| } | ||
|
|
||
| if (record.email !== userInfo.email) { | ||
| this.logger.warn(`Email mismatch for OTP verification.`); | ||
| return { | ||
| code: 'otp_email_mismatch', | ||
| message: `Email mismatch for OTP verification.`, | ||
| }; | ||
| } | ||
|
|
||
| if (record.action_type !== actionType) { | ||
| this.logger.warn(`Action type mismatch for OTP verification.`); | ||
| return { | ||
| code: 'otp_action_type_mismatch', | ||
| message: `Action type mismatch for OTP verification.`, | ||
| }; | ||
| } | ||
|
|
||
| if (record.expiration_time && record.expiration_time < new Date()) { | ||
| this.logger.warn(`OTP code has expired.`); | ||
| return { code: 'otp_expired', message: `OTP code has expired.` }; | ||
| } | ||
|
|
||
| if (record.verified_at !== null) { | ||
| this.logger.warn(`OTP code has already been verified.`); | ||
| return { | ||
| code: 'otp_already_verified', | ||
| message: `OTP code has already been verified.`, | ||
| }; | ||
| } | ||
|
|
||
| this.logger.log( | ||
| `OTP code ${otpCode} verified successfully for action ${actionType}`, | ||
| ); | ||
|
|
||
| this.logger.log( | ||
| `OTP code ${otpCode} verified successfully for action ${actionType}`, | ||
| ); | ||
| await tx.otp.update({ | ||
| where: { | ||
| id: record.id, | ||
| }, | ||
| data: { | ||
| verified_at: new Date(), | ||
| }, | ||
| }); | ||
|
|
||
| await this.prisma.otp.update({ | ||
| where: { | ||
| id: record.id, | ||
| }, | ||
| data: { | ||
| verified_at: new Date(), | ||
| }, | ||
| return { code: 'success' }; | ||
| }); | ||
|
|
||
| return { code: 'success' }; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[⚠️
maintainability]Consider using a more specific error type or class for the thrown error instead of a generic
Error. This can improve error handling and make it easier to distinguish different error types in the codebase.