|
1 | 1 | import { Injectable, Logger } from '@nestjs/common'; |
2 | 2 | import { PrismaService } from './prisma.service'; |
3 | 3 | import crypto from 'crypto'; |
4 | | -import { reference_type } from '@prisma/client'; |
| 4 | +import { otp, reference_type } from '@prisma/client'; |
5 | 5 | import { ENV_CONFIG } from 'src/config'; |
6 | 6 | import { TopcoderEmailService } from '../topcoder/tc-email.service'; |
7 | 7 | import { BasicMemberInfo } from '../topcoder'; |
@@ -104,62 +104,65 @@ export class OtpService { |
104 | 104 | userInfo: BasicMemberInfo, |
105 | 105 | actionType: reference_type, |
106 | 106 | ) { |
107 | | - const record = await this.prisma.otp.findFirst({ |
108 | | - where: { |
109 | | - otp_hash: hashOtp(otpCode), |
110 | | - }, |
111 | | - orderBy: { |
112 | | - expiration_time: 'desc', |
113 | | - }, |
114 | | - }); |
115 | | - |
116 | | - if (!record) { |
117 | | - this.logger.warn(`No OTP record found for the provided code.`); |
118 | | - return { code: 'otp_invalid', message: `Invalid OTP code.` }; |
119 | | - } |
120 | | - |
121 | | - if (record.email !== userInfo.email) { |
122 | | - this.logger.warn(`Email mismatch for OTP verification.`); |
123 | | - return { |
124 | | - code: 'otp_email_mismatch', |
125 | | - message: `Email mismatch for OTP verification.`, |
126 | | - }; |
127 | | - } |
128 | | - |
129 | | - if (record.action_type !== actionType) { |
130 | | - this.logger.warn(`Action type mismatch for OTP verification.`); |
131 | | - return { |
132 | | - code: 'otp_action_type_mismatch', |
133 | | - message: `Action type mismatch for OTP verification.`, |
134 | | - }; |
135 | | - } |
136 | | - |
137 | | - if (record.expiration_time && record.expiration_time < new Date()) { |
138 | | - this.logger.warn(`OTP code has expired.`); |
139 | | - return { code: 'otp_expired', message: `OTP code has expired.` }; |
140 | | - } |
141 | | - |
142 | | - if (record.verified_at !== null) { |
143 | | - this.logger.warn(`OTP code has already been verified.`); |
144 | | - return { |
145 | | - code: 'otp_already_verified', |
146 | | - message: `OTP code has already been verified.`, |
147 | | - }; |
148 | | - } |
| 107 | + return await this.prisma.$transaction(async (tx) => { |
| 108 | + const records = await tx.$queryRaw<otp>` |
| 109 | + SELECT id, email, otp_hash, expiration_time, action_type, created_at, updated_at, verified_at |
| 110 | + FROM otp |
| 111 | + WHERE otp_hash=${hashOtp(otpCode)} |
| 112 | + ORDER BY expiration_time DESC |
| 113 | + LIMIT 1 |
| 114 | + FOR UPDATE NOWAIT; |
| 115 | + `; |
| 116 | + const record = records[0]; |
| 117 | + |
| 118 | + if (!record) { |
| 119 | + this.logger.warn(`No OTP record found for the provided code.`); |
| 120 | + return { code: 'otp_invalid', message: `Invalid OTP code.` }; |
| 121 | + } |
| 122 | + |
| 123 | + if (record.email !== userInfo.email) { |
| 124 | + this.logger.warn(`Email mismatch for OTP verification.`); |
| 125 | + return { |
| 126 | + code: 'otp_email_mismatch', |
| 127 | + message: `Email mismatch for OTP verification.`, |
| 128 | + }; |
| 129 | + } |
| 130 | + |
| 131 | + if (record.action_type !== actionType) { |
| 132 | + this.logger.warn(`Action type mismatch for OTP verification.`); |
| 133 | + return { |
| 134 | + code: 'otp_action_type_mismatch', |
| 135 | + message: `Action type mismatch for OTP verification.`, |
| 136 | + }; |
| 137 | + } |
| 138 | + |
| 139 | + if (record.expiration_time && record.expiration_time < new Date()) { |
| 140 | + this.logger.warn(`OTP code has expired.`); |
| 141 | + return { code: 'otp_expired', message: `OTP code has expired.` }; |
| 142 | + } |
| 143 | + |
| 144 | + if (record.verified_at !== null) { |
| 145 | + this.logger.warn(`OTP code has already been verified.`); |
| 146 | + return { |
| 147 | + code: 'otp_already_verified', |
| 148 | + message: `OTP code has already been verified.`, |
| 149 | + }; |
| 150 | + } |
| 151 | + |
| 152 | + this.logger.log( |
| 153 | + `OTP code ${otpCode} verified successfully for action ${actionType}`, |
| 154 | + ); |
149 | 155 |
|
150 | | - this.logger.log( |
151 | | - `OTP code ${otpCode} verified successfully for action ${actionType}`, |
152 | | - ); |
| 156 | + await tx.otp.update({ |
| 157 | + where: { |
| 158 | + id: record.id, |
| 159 | + }, |
| 160 | + data: { |
| 161 | + verified_at: new Date(), |
| 162 | + }, |
| 163 | + }); |
153 | 164 |
|
154 | | - await this.prisma.otp.update({ |
155 | | - where: { |
156 | | - id: record.id, |
157 | | - }, |
158 | | - data: { |
159 | | - verified_at: new Date(), |
160 | | - }, |
| 165 | + return { code: 'success' }; |
161 | 166 | }); |
162 | | - |
163 | | - return { code: 'success' }; |
164 | 167 | } |
165 | 168 | } |
0 commit comments