Totpcode resend by uid

This commit is contained in:
Maxime Lalo 2023-12-01 09:49:13 +01:00
parent 6e2d45c8cc
commit af4f51eaab
2 changed files with 30 additions and 22 deletions

View File

@ -30,17 +30,16 @@ export default class AuthController extends ApiController {
} }
try { try {
const customer = await this.customerService.verifyEmail2FASms(email); const res = await this.customerService.verifyEmail2FASms(email);
if (!customer) { if (!res) {
this.httpNotFoundRequest(response, "Customer not found"); this.httpNotFoundRequest(response, "Customer not found");
return; return;
} }
this.httpSuccess(response, { partialPhoneNumber: customer.contact?.cell_phone_number.replace(/\s/g, "").slice(-4) }); this.httpSuccess(response, {
partialPhoneNumber: res.customer.contact?.cell_phone_number.replace(/\s/g, "").slice(-4),
totpCodeUid: res.totpCode.uid,
});
} catch (error) { } catch (error) {
if (error instanceof SmsNotExpiredError) {
this.httpTooEarlyRequest(response, error.message);
return;
}
console.log(error); console.log(error);
this.httpInternalError(response); this.httpInternalError(response);
} }
@ -207,18 +206,27 @@ export default class AuthController extends ApiController {
@Post("/api/v1/customer/auth/send-another-code") @Post("/api/v1/customer/auth/send-another-code")
protected async sendAnotherCode(req: Request, response: Response) { protected async sendAnotherCode(req: Request, response: Response) {
const email = req.body["email"]; const email = req.body["email"];
const totpCodeUid = req.body["totpCodeUid"];
if (!email) { if (!email) {
this.httpBadRequest(response, "email is required"); this.httpBadRequest(response, "email is required");
return; return;
} }
if (!totpCodeUid) {
this.httpBadRequest(response, "totpCodeUid is required");
return;
}
try { try {
const customer = await this.customerService.askAnotherCode(email); const res = await this.customerService.askAnotherCode(email, totpCodeUid);
if (!customer) { if (!res) {
this.httpNotFoundRequest(response, "Customer not found"); this.httpNotFoundRequest(response, "Customer not found");
return; return;
} }
this.httpSuccess(response, { partialPhoneNumber: customer.contact?.cell_phone_number.replace(/\s/g, "").slice(-4) }); this.httpSuccess(response, {
partialPhoneNumber: res.customer.contact?.cell_phone_number.replace(/\s/g, "").slice(-4),
totpCodeUid: res.totpCode.uid,
});
} catch (error) { } catch (error) {
if (error instanceof TooSoonForNewCode || error instanceof TotpCodeExpiredError) { if (error instanceof TooSoonForNewCode || error instanceof TotpCodeExpiredError) {
this.httpUnauthorized(response, error.message); this.httpUnauthorized(response, error.message);

View File

@ -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 | null> { public async verifyEmail2FASms(email: string): Promise<{ customer: Customer; totpCode: TotpCodes } | 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;
@ -100,18 +100,18 @@ export default class CustomersService extends BaseService {
const validTotpCode = customerHydrated.totpCodes?.find((totpCode) => { const validTotpCode = customerHydrated.totpCodes?.find((totpCode) => {
return totpCode.expire_at && totpCode.expire_at.getTime() > now; return totpCode.expire_at && totpCode.expire_at.getTime() > now;
}); });
if (validTotpCode) throw new SmsNotExpiredError(); if (validTotpCode) return { customer, totpCode: validTotpCode };
// 3: Generate a new SMS code // 3: Generate a new SMS code
const totpPin = this.generateTotp(); const totpPin = this.generateTotp();
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
await this.saveTotpPin(customer, totpPin, new Date(now + 5 * 60000), reason); const totpCode = await this.saveTotpPin(customer, totpPin, new Date(now + 5 * 60000), reason);
// 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; return { customer, totpCode };
} }
/** /**
@ -258,7 +258,7 @@ export default class CustomersService extends BaseService {
); );
} }
public async askAnotherCode(email: string): Promise<Customer | null> { public async askAnotherCode(email: string, totpCodeUid: string): Promise<{ customer: Customer; totpCode: TotpCodes } | 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;
@ -267,26 +267,26 @@ export default class CustomersService extends BaseService {
const customerHydrated = Customer.hydrate<Customer>(customer); const customerHydrated = Customer.hydrate<Customer>(customer);
// 2: Get last code sent // 2: Get last code sent
const lastCode = customerHydrated.totpCodes?.find((totpCode) => { const totpCodeToResend = customerHydrated.totpCodes?.find((totpCode) => {
return totpCode.expire_at && totpCode.expire_at.getTime() > now; return totpCode.uid && totpCodeUid;
}); });
if (!lastCode) 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 (lastCode.created_at && lastCode.created_at.getTime() > now - 30000) throw new TooSoonForNewCode(); if (totpCodeToResend.created_at && totpCodeToResend.created_at.getTime() > now - 30000) throw new TooSoonForNewCode();
// 4: Generate a new SMS code // 4: Generate a new SMS code
const totpPin = this.generateTotp(); const totpPin = this.generateTotp();
// 5: Disable the old code // 5: Disable the old code
await this.totpCodesRepository.disable(lastCode); await this.totpCodesRepository.disable(totpCodeToResend);
// 6: Save the SMS code in database // 6: Save the SMS code in database
await this.saveTotpPin(customer, totpPin, new Date(now + 5 * 60000), lastCode.reason!); const totpCode = await this.saveTotpPin(customer, totpPin, new Date(now + 5 * 60000), totpCodeToResend.reason!);
// 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);
return customer; return { customer, totpCode };
} }
/** /**