✨ Refacto set first password
This commit is contained in:
parent
d3f9527f85
commit
97fd3f0d86
@ -7,6 +7,7 @@ import CustomersService, {
|
|||||||
InvalidPasswordError,
|
InvalidPasswordError,
|
||||||
InvalidTotpCodeError,
|
InvalidTotpCodeError,
|
||||||
NotRegisteredCustomerError,
|
NotRegisteredCustomerError,
|
||||||
|
PasswordAlreadySetError,
|
||||||
SmsNotExpiredError,
|
SmsNotExpiredError,
|
||||||
TotpCodeExpiredError,
|
TotpCodeExpiredError,
|
||||||
} from "@Services/customer/CustomersService/CustomersService";
|
} from "@Services/customer/CustomersService/CustomersService";
|
||||||
@ -115,47 +116,29 @@ export default class AuthController extends ApiController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const customer = await this.customerService.getOne({
|
|
||||||
where: {
|
|
||||||
contact: {
|
|
||||||
email,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
contact: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!customer) {
|
|
||||||
this.httpNotFoundRequest(response, "Customer not found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customer.password) {
|
|
||||||
this.httpBadRequest(response, "Password already set, please login");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!customer.smsCode) {
|
|
||||||
this.httpBadRequest(response, "No sms code found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (customer.smsCode !== smsCode) {
|
|
||||||
this.httpBadRequest(response, "Invalid sms code");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hashedPassword = await this.authService.hashPassword(password);
|
|
||||||
await this.customerService.setPassword(customer, hashedPassword);
|
|
||||||
|
|
||||||
const customerHydrated = Customer.hydrate<Customer>(customer);
|
|
||||||
const payload = await this.authService.getCustomerJwtPayload([customerHydrated]);
|
|
||||||
const accessToken = this.authService.generateAccessToken(payload);
|
|
||||||
const refreshToken = this.authService.generateRefreshToken(payload);
|
|
||||||
try {
|
try {
|
||||||
|
const customer = await this.customerService.setFirstPassword(email, smsCode, password);
|
||||||
|
if (!customer) {
|
||||||
|
this.httpBadRequest(response, "Customer not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const customerHydrated = Customer.hydrate<Customer>(customer);
|
||||||
|
const payload = await this.authService.getCustomerJwtPayload([customerHydrated]);
|
||||||
|
const accessToken = this.authService.generateAccessToken(payload);
|
||||||
|
const refreshToken = this.authService.generateRefreshToken(payload);
|
||||||
this.httpSuccess(response, { accessToken, refreshToken });
|
this.httpSuccess(response, { accessToken, refreshToken });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
if (error instanceof TotpCodeExpiredError || error instanceof PasswordAlreadySetError) {
|
||||||
|
this.httpBadRequest(response, error.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error instanceof InvalidTotpCodeError) {
|
||||||
|
this.httpUnauthorized(response, error.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log(error);
|
console.log(error);
|
||||||
this.httpInternalError(response);
|
this.httpInternalError(response);
|
||||||
return;
|
return;
|
||||||
|
@ -34,6 +34,12 @@ export class InvalidPasswordError extends Error {
|
|||||||
super("Invalid password");
|
super("Invalid password");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class PasswordAlreadySetError extends Error {
|
||||||
|
constructor() {
|
||||||
|
super("Password already set");
|
||||||
|
}
|
||||||
|
}
|
||||||
@Service()
|
@Service()
|
||||||
export default class CustomersService extends BaseService {
|
export default class CustomersService extends BaseService {
|
||||||
constructor(private customerRepository: CustomersRepository, private authService: AuthService) {
|
constructor(private customerRepository: CustomersRepository, private authService: AuthService) {
|
||||||
@ -56,10 +62,6 @@ export default class CustomersService extends BaseService {
|
|||||||
return this.customerRepository.findOne(query);
|
return this.customerRepository.findOne(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async userExistsByEmail(email: string): Promise<boolean> {
|
|
||||||
return !!(await this.getByEmail(email));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description : Send SMS to verify the email of a customer (2FA)
|
* @description : Send SMS to verify the email of a customer (2FA)
|
||||||
* 1: Check if the customer exists
|
* 1: Check if the customer exists
|
||||||
@ -85,56 +87,42 @@ export default class CustomersService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description : Saves a TotpPin in database
|
* @description : Set the password of a customer when it's the first time they connect
|
||||||
|
* 1: Check if the customer exists
|
||||||
|
* 2: Check if the password is already set
|
||||||
|
* 3: Check if the SMS code is existing and is not expired
|
||||||
|
* 4: Check if the SMS code is valid
|
||||||
|
* 5: Hash the password
|
||||||
|
* 6: Set the password in database
|
||||||
|
* 7: Returns the customer
|
||||||
|
* @param email
|
||||||
|
* @param smsCode
|
||||||
|
* @param password
|
||||||
|
* @returns
|
||||||
*/
|
*/
|
||||||
private async saveTotpPin(customer: Customer, totpPin: number, expireAt: Date) {
|
public async setFirstPassword(email: string, smsCode: string, password: string): Promise<Customer | null> {
|
||||||
return await this.customerRepository.update(
|
// 1: Check if the customer exists
|
||||||
customer.uid as string,
|
const customer = await this.getByEmail(email);
|
||||||
Customer.hydrate<Customer>({
|
if (!customer) return null;
|
||||||
...customer,
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
smsCode: totpPin.toString(),
|
|
||||||
smsCodeExpire: expireAt,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private generateTotp() {
|
// 2: Check if the password is already set
|
||||||
return Math.floor(100000 + Math.random() * 900000);
|
if (customer.password) throw new PasswordAlreadySetError();
|
||||||
}
|
|
||||||
|
|
||||||
private async sendSmsCodeToCustomer(totpPin: number, customer: Customer) {
|
// 3: Check if the SMS code is existing and is not expired
|
||||||
console.log(totpPin);
|
if (!customer.smsCode || !customer.smsCodeExpire || new Date().getTime() > customer.smsCodeExpire.getTime())
|
||||||
}
|
throw new TotpCodeExpiredError();
|
||||||
|
|
||||||
/**
|
// 4: Check if the SMS code is valid
|
||||||
* @description : Set password for a customer
|
if (customer.smsCode !== smsCode) throw new InvalidTotpCodeError();
|
||||||
* @throws {Error} If customer cannot be updated
|
|
||||||
*/
|
|
||||||
public async setPassword(customer: Customer, password: string) {
|
|
||||||
return await this.customerRepository.update(
|
|
||||||
customer.uid as string,
|
|
||||||
Customer.hydrate<Customer>({
|
|
||||||
...customer,
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
password,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getByEmail(email: string) {
|
// 5: Hash the password
|
||||||
return this.customerRepository.findOne({
|
const hashedPassword = await this.authService.hashPassword(password);
|
||||||
where: {
|
|
||||||
contact: {
|
// 6: Set the password in database
|
||||||
email,
|
await this.setPassword(customer, hashedPassword);
|
||||||
},
|
|
||||||
},
|
// 7: Returns the customer
|
||||||
include: {
|
return customer;
|
||||||
contact: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -173,4 +161,57 @@ export default class CustomersService extends BaseService {
|
|||||||
// 6: Return the customer
|
// 6: Return the customer
|
||||||
return customer;
|
return customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Set password for a customer
|
||||||
|
* @throws {Error} If customer cannot be updated
|
||||||
|
*/
|
||||||
|
private async setPassword(customer: Customer, password: string) {
|
||||||
|
return await this.customerRepository.update(
|
||||||
|
customer.uid as string,
|
||||||
|
Customer.hydrate<Customer>({
|
||||||
|
...customer,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
password,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getByEmail(email: string) {
|
||||||
|
return this.customerRepository.findOne({
|
||||||
|
where: {
|
||||||
|
contact: {
|
||||||
|
email,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
contact: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description : Saves a TotpPin in database
|
||||||
|
*/
|
||||||
|
private async saveTotpPin(customer: Customer, totpPin: number, expireAt: Date) {
|
||||||
|
return await this.customerRepository.update(
|
||||||
|
customer.uid as string,
|
||||||
|
Customer.hydrate<Customer>({
|
||||||
|
...customer,
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
smsCode: totpPin.toString(),
|
||||||
|
smsCodeExpire: expireAt,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateTotp() {
|
||||||
|
return Math.floor(100000 + Math.random() * 900000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async sendSmsCodeToCustomer(totpPin: number, customer: Customer) {
|
||||||
|
console.log(totpPin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user