✨ Send another code working
This commit is contained in:
parent
8ef401b4b2
commit
9dc1049ce7
@ -202,4 +202,29 @@ export default class AuthController extends ApiController {
|
||||
this.httpInternalError(response);
|
||||
}
|
||||
}
|
||||
|
||||
@Post("/api/v1/customer/auth/send-another-code")
|
||||
protected async sendAnotherCode(req: Request, response: Response) {
|
||||
const email = req.body["email"];
|
||||
if (!email) {
|
||||
this.httpBadRequest(response, "email is required");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const customer = await this.customerService.askAnotherCode(email);
|
||||
if (!customer) {
|
||||
this.httpNotFoundRequest(response, "Customer not found");
|
||||
return;
|
||||
}
|
||||
this.httpSuccess(response, { partialPhoneNumber: customer.contact?.cell_phone_number.replace(/\s/g, "").slice(-4) });
|
||||
} catch (error) {
|
||||
if (error instanceof InvalidTotpCodeError || error instanceof TotpCodeExpiredError) {
|
||||
this.httpUnauthorized(response, error.message);
|
||||
return;
|
||||
}
|
||||
console.log(error);
|
||||
this.httpInternalError(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,8 @@ CREATE TABLE "totp_codes" (
|
||||
"code" VARCHAR(255) NOT NULL,
|
||||
"reason" "TotpCodesReasons" NOT NULL DEFAULT 'LOGIN',
|
||||
"expire_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
"created_at" TIMESTAMP(3) DEFAULT CURRENT_TIMESTAMP,
|
||||
"updated_at" TIMESTAMP(3),
|
||||
CONSTRAINT "totp_codes_pkey" PRIMARY KEY ("uid")
|
||||
);
|
||||
|
||||
|
@ -343,13 +343,14 @@ model Votes {
|
||||
}
|
||||
|
||||
model TotpCodes {
|
||||
uid String @id @unique @default(uuid())
|
||||
customer Customers @relation(fields: [customer_uid], references: [uid], onDelete: Cascade)
|
||||
customer_uid String @db.VarChar(255)
|
||||
code String @db.VarChar(255)
|
||||
uid String @id @unique @default(uuid())
|
||||
customer Customers @relation(fields: [customer_uid], references: [uid], onDelete: Cascade)
|
||||
customer_uid String @db.VarChar(255)
|
||||
code String @db.VarChar(255)
|
||||
reason TotpCodesReasons @default(LOGIN)
|
||||
expire_at DateTime? @default(now())
|
||||
|
||||
expire_at DateTime? @default(now())
|
||||
created_at DateTime? @default(now())
|
||||
updated_at DateTime? @updatedAt
|
||||
@@map("totp_codes")
|
||||
}
|
||||
|
||||
|
@ -4,11 +4,6 @@ import { Service } from "typedi";
|
||||
import { Prisma, TotpCodes } from "@prisma/client";
|
||||
import { TotpCodes as TotpCode } from "le-coffre-resources/dist/Customer";
|
||||
|
||||
type IExcludedTotpCodesVars = {
|
||||
code?: string;
|
||||
expire_at?: Date;
|
||||
};
|
||||
|
||||
@Service()
|
||||
export default class TotpCodesRepository extends BaseRepository {
|
||||
constructor(private database: Database) {
|
||||
@ -42,17 +37,17 @@ export default class TotpCodesRepository extends BaseRepository {
|
||||
/**
|
||||
* @description : Create a totp code
|
||||
*/
|
||||
public async create(totpCode: TotpCode, excludedVars: IExcludedTotpCodesVars): Promise<TotpCodes> {
|
||||
public async create(totpCode: TotpCode): Promise<TotpCodes> {
|
||||
const createArgs: Prisma.TotpCodesCreateArgs = {
|
||||
data: {
|
||||
code: excludedVars.code!,
|
||||
code: totpCode.code!,
|
||||
reason: totpCode.reason!,
|
||||
customer: {
|
||||
connect: {
|
||||
uid: totpCode.customer_uid!,
|
||||
},
|
||||
},
|
||||
expire_at: excludedVars.expire_at!,
|
||||
expire_at: totpCode.expire_at!,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -246,6 +246,37 @@ export default class CustomersService extends BaseService {
|
||||
);
|
||||
}
|
||||
|
||||
public async askAnotherCode(email: string): Promise<Customer | null> {
|
||||
// 1: Check if the customer exists
|
||||
const customer = await this.getByEmail(email);
|
||||
if (!customer) return null;
|
||||
const now = new Date().getTime();
|
||||
|
||||
const customerHydrated = Customer.hydrate<Customer>(customer);
|
||||
|
||||
// 2: Get last code sent
|
||||
const lastCode = customerHydrated.totpCodes?.find((totpCode) => {
|
||||
return totpCode.expire_at && totpCode.expire_at.getTime() > now;
|
||||
});
|
||||
if (!lastCode) throw new SmsNotExpiredError();
|
||||
|
||||
// 3: Check if it was created more than 30 seconds ago
|
||||
if (lastCode.created_at && lastCode.created_at.getTime() > now - 30000) throw new SmsNotExpiredError();
|
||||
|
||||
// 4: Generate a new SMS code
|
||||
const totpPin = this.generateTotp();
|
||||
|
||||
// 5: Disable the old code
|
||||
await this.totpCodesRepository.disable(lastCode);
|
||||
|
||||
// 6: Save the SMS code in database
|
||||
await this.saveTotpPin(customer, totpPin, new Date(now + 5 * 60000), lastCode.reason!);
|
||||
|
||||
// 7: Send the SMS code to the customer
|
||||
await this.sendSmsCodeToCustomer(totpPin, customer);
|
||||
return customer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description : Set password for a customer
|
||||
* @throws {Error} If customer cannot be updated
|
||||
@ -286,11 +317,10 @@ export default class CustomersService extends BaseService {
|
||||
reason,
|
||||
customer_uid: customer.uid,
|
||||
customer: Customer.hydrate<Customer>(customer),
|
||||
}),
|
||||
{
|
||||
created_at: new Date(),
|
||||
code: totpPin.toString(),
|
||||
expire_at: expireAt,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return await this.customerRepository.update(
|
||||
customer.uid as string,
|
||||
|
Loading…
x
Reference in New Issue
Block a user