Can now resend sms right away

This commit is contained in:
Maxime Lalo 2023-12-01 16:36:20 +01:00
parent 53fe77ac73
commit 56fe8a43b4
5 changed files with 31 additions and 18 deletions

View File

@ -57,7 +57,7 @@
"file-type-checker": "^1.0.8", "file-type-checker": "^1.0.8",
"fp-ts": "^2.16.1", "fp-ts": "^2.16.1",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.99", "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.102",
"module-alias": "^2.2.2", "module-alias": "^2.2.2",
"monocle-ts": "^2.3.13", "monocle-ts": "^2.3.13",
"multer": "^1.4.5-lts.1", "multer": "^1.4.5-lts.1",

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "totp_codes" ADD COLUMN "resent" BOOLEAN NOT NULL DEFAULT false;

View File

@ -348,6 +348,7 @@ model TotpCodes {
customer_uid String @db.VarChar(255) customer_uid String @db.VarChar(255)
code String @db.VarChar(255) code String @db.VarChar(255)
reason TotpCodesReasons @default(LOGIN) reason TotpCodesReasons @default(LOGIN)
resent Boolean @default(false)
expire_at DateTime? @default(now()) expire_at DateTime? @default(now())
created_at DateTime? @default(now()) created_at DateTime? @default(now())
updated_at DateTime? @updatedAt updated_at DateTime? @updatedAt

View File

@ -48,6 +48,7 @@ export default class TotpCodesRepository extends BaseRepository {
}, },
}, },
expire_at: totpCode.expire_at!, expire_at: totpCode.expire_at!,
resent: totpCode.resent!,
}, },
}; };
@ -64,6 +65,7 @@ export default class TotpCodesRepository extends BaseRepository {
}, },
data: { data: {
expire_at: new Date(), expire_at: new Date(),
resent: true,
}, },
}); });
} }

View File

@ -1,10 +1,10 @@
import { BackendVariables } from "@Common/config/variables/Variables"; import { BackendVariables } from "@Common/config/variables/Variables";
import { Customers, Prisma } from "@prisma/client"; import { Customers, Prisma, TotpCodes } from "@prisma/client";
import CustomersRepository from "@Repositories/CustomersRepository"; import CustomersRepository from "@Repositories/CustomersRepository";
import TotpCodesRepository from "@Repositories/TotpCodesRepository"; import TotpCodesRepository from "@Repositories/TotpCodesRepository";
import BaseService from "@Services/BaseService"; import BaseService from "@Services/BaseService";
import AuthService from "@Services/common/AuthService/AuthService"; import AuthService from "@Services/common/AuthService/AuthService";
import TotpCodes, { TotpCodesReasons } from "le-coffre-resources/dist/Customer/TotpCodes"; import TotpCodesResource, { TotpCodesReasons } from "le-coffre-resources/dist/Customer/TotpCodes";
import { Customer } from "le-coffre-resources/dist/Notary"; import { Customer } from "le-coffre-resources/dist/Notary";
import { Service } from "typedi"; import { Service } from "typedi";
import OvhService from "@Services/common/OvhService/OvhService"; import OvhService from "@Services/common/OvhService/OvhService";
@ -88,7 +88,7 @@ export default class CustomersService extends BaseService {
* 4: Save the SMS code in database * 4: Save the SMS code in database
* 5: Send the SMS code to the customer * 5: Send the SMS code to the customer
*/ */
public async verifyEmail2FASms(email: string): Promise<{ customer: Customer; totpCode: TotpCodes } | null> { public async verifyEmail2FASms(email: string): Promise<{ customer: Customer; totpCode: TotpCodesResource } | null> {
// 1: Check if the customer exists // 1: Check if the customer exists
const customer = await this.getByEmail(email); const customer = await this.getByEmail(email);
if (!customer) return null; if (!customer) return null;
@ -108,10 +108,16 @@ export default class CustomersService extends BaseService {
const reason = customer.password ? TotpCodesReasons.LOGIN : TotpCodesReasons.FIRST_LOGIN; const reason = customer.password ? TotpCodesReasons.LOGIN : TotpCodesReasons.FIRST_LOGIN;
// 4: Save the SMS code in database // 4: Save the SMS code in database
const totpCode = await this.saveTotpPin(customer, totpPin, new Date(now + 5 * 60000), reason); const totpCode = await this.saveTotpPin(customer, totpPin, new Date(now + 5 * 60000), reason);
if (!totpCode) return null;
// 5: Send the SMS code to the customer // 5: Send the SMS code to the customer
await this.sendSmsCodeToCustomer(totpPin, customer); await this.sendSmsCodeToCustomer(totpPin, customer);
return { customer, totpCode }; return {
customer,
totpCode: TotpCodesResource.hydrate<TotpCodesResource>({
...totpCode,
reason: totpCode.reason as TotpCodesReasons,
}),
};
} }
/** /**
@ -273,7 +279,8 @@ export default class CustomersService extends BaseService {
if (!totpCodeToResend) throw new TotpCodeExpiredError(); if (!totpCodeToResend) throw new TotpCodeExpiredError();
// 3: Check if it was created more than 30 seconds ago // 3: Check if it was created more than 30 seconds ago
if (totpCodeToResend.created_at && totpCodeToResend.created_at.getTime() > now - 30000) throw new TooSoonForNewCode(); if (totpCodeToResend.created_at && totpCodeToResend.created_at.getTime() > now - 30000 && totpCodeToResend.resent)
throw new TooSoonForNewCode();
// 4: Generate a new SMS code // 4: Generate a new SMS code
const totpPin = this.generateTotp(); const totpPin = this.generateTotp();
@ -282,7 +289,7 @@ export default class CustomersService extends BaseService {
await this.totpCodesRepository.disable(totpCodeToResend); await this.totpCodesRepository.disable(totpCodeToResend);
// 6: Save the SMS code in database // 6: Save the SMS code in database
const totpCode = await this.saveTotpPin(customer, totpPin, new Date(now + 5 * 60000), totpCodeToResend.reason!); const totpCode = await this.saveTotpPin(customer, totpPin, new Date(now + 5 * 60000), totpCodeToResend.reason!, true);
// 7: Send the SMS code to the customer // 7: Send the SMS code to the customer
await this.sendSmsCodeToCustomer(totpPin, customer); await this.sendSmsCodeToCustomer(totpPin, customer);
@ -322,22 +329,23 @@ export default class CustomersService extends BaseService {
/** /**
* @description : Saves a TotpPin in database * @description : Saves a TotpPin in database
*/ */
private async saveTotpPin(customer: Customer, totpPin: number, expireAt: Date, reason: TotpCodesReasons) { private async saveTotpPin(
customer: Customer,
totpPin: number,
expireAt: Date,
reason: TotpCodesReasons,
resent?: boolean,
): Promise<TotpCodes> {
// Create the totpCode in table using repository // Create the totpCode in table using repository
await this.totpCodesRepository.create( return await this.totpCodesRepository.create(
TotpCodes.hydrate<TotpCodes>({ TotpCodesResource.hydrate<TotpCodesResource>({
reason, reason,
customer_uid: customer.uid, customer_uid: customer.uid,
customer: Customer.hydrate<Customer>(customer), customer: Customer.hydrate<Customer>(customer),
created_at: new Date(), created_at: new Date(),
code: totpPin.toString(), code: totpPin.toString(),
expire_at: expireAt, expire_at: expireAt,
}), resent: resent || false,
);
return await this.customerRepository.update(
customer.uid as string,
Customer.hydrate<Customer>({
...customer,
}), }),
); );
} }
@ -371,7 +379,7 @@ export default class CustomersService extends BaseService {
* @param email * @param email
* @returns * @returns
*/ */
public async verifyTotpCode(totpCode: string, email: string): Promise<TotpCodes | null> { public async verifyTotpCode(totpCode: string, email: string): Promise<TotpCodesResource | null> {
// 1: Check if the customer exists // 1: Check if the customer exists
const customer = await this.getByEmail(email); const customer = await this.getByEmail(email);
if (!customer) return null; if (!customer) return null;