diff --git a/api/src/modules/admin/admin.controller.ts b/api/src/modules/admin/admin.controller.ts index d1066f40..5a833cc7 100644 --- a/api/src/modules/admin/admin.controller.ts +++ b/api/src/modules/admin/admin.controller.ts @@ -1,4 +1,4 @@ -import { Controller, UseGuards } from '@nestjs/common'; +import { Controller, Headers, UseGuards } from '@nestjs/common'; import { RolesGuard } from '@api/modules/auth/guards/roles.guard'; import { JwtAuthGuard } from '@api/modules/auth/guards/jwt-auth.guard'; import { RequiredRoles } from '@api/modules/auth/decorators/roles.decorator'; @@ -14,10 +14,12 @@ export class AdminController { constructor(private readonly auth: AuthenticationService) {} @RequiredRoles(ROLES.ADMIN) - @TsRestHandler(adminContract.createUser) - async createUser(): Promise { - return tsRestHandler(adminContract.createUser, async ({ body }) => { - await this.auth.createUser(body); + @TsRestHandler(adminContract.addUser) + async createUser( + @Headers('origin') origin: string, + ): Promise { + return tsRestHandler(adminContract.addUser, async ({ body }) => { + await this.auth.addUser(origin, body); return { status: 201, body: null, diff --git a/api/src/modules/auth/authentication.service.ts b/api/src/modules/auth/authentication.service.ts index 198c97dd..585f4179 100644 --- a/api/src/modules/auth/authentication.service.ts +++ b/api/src/modules/auth/authentication.service.ts @@ -1,4 +1,4 @@ -import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { Injectable, Logger, UnauthorizedException } from '@nestjs/common'; import { UsersService } from '@api/modules/users/users.service'; import { User } from '@shared/entities/users/user.entity'; import * as bcrypt from 'bcrypt'; @@ -15,6 +15,7 @@ import { UpdateUserPasswordDto } from '@shared/dtos/users/update-user-password.d @Injectable() export class AuthenticationService { + logger: Logger = new Logger(AuthenticationService.name); constructor( private readonly usersService: UsersService, private readonly jwtManager: JwtManager, @@ -29,21 +30,37 @@ export class AuthenticationService { throw new UnauthorizedException(`Invalid credentials`); } - async createUser(createUser: CreateUserDto): Promise { + async addUser(origin: string, dto: CreateUserDto) { + const { newUser, plainTextPassword } = await this.createUser(dto); + try { + await this.commandBus.execute( + new SendWelcomeEmailCommand(newUser, plainTextPassword, origin), + ); + } catch (e) { + await this.usersService.delete(newUser); + this.logger.error(e); + throw e; + } + } + + async createUser( + createUser: CreateUserDto, + ): Promise<{ newUser: User; plainTextPassword: string }> { // TODO: This is sync, check how to improve it const { email, name, partnerName } = createUser; const plainTextPassword = randomBytes(8).toString('hex'); const passwordHash = await bcrypt.hash(plainTextPassword, 10); - const newUser = await this.usersService.createUser({ + const newUser = await this.usersService.saveUser({ name, email, password: passwordHash, partnerName, isActive: false, }); - await this.commandBus - .execute(new SendWelcomeEmailCommand(newUser, plainTextPassword)) - .catch(() => this.usersService.delete(newUser)); + return { + newUser, + plainTextPassword, + }; } async logIn(user: User): Promise { @@ -53,11 +70,12 @@ export class AuthenticationService { async signUp(user: User, signUpDto: SignUpDto): Promise { const { oneTimePassword, newPassword } = signUpDto; - if (!(await bcrypt.compare(oneTimePassword, user.password))) { + if (await this.isPasswordValid(user, oneTimePassword)) { throw new UnauthorizedException(); } user.isActive = true; - await this.usersService.saveNewHashedPassword(user, newPassword); + user.password = await this.hashPassword(newPassword); + await this.usersService.saveUser(user); this.eventBus.publish(new UserSignedUpEvent(user.id, user.email)); } @@ -71,20 +89,22 @@ export class AuthenticationService { async updatePassword(user: User, dto: UpdateUserPasswordDto): Promise { const { password, newPassword } = dto; if (await this.isPasswordValid(user, password)) { - return this.usersService.saveNewHashedPassword(user, newPassword); + user.password = await this.hashPassword(newPassword); + return this.usersService.saveUser(user); } throw new UnauthorizedException(); } async resetPassword(user: User, newPassword: string): Promise { - await this.usersService.saveNewHashedPassword(user, newPassword); + user.password = await this.hashPassword(newPassword); + await this.usersService.saveUser(user); } async isPasswordValid(user: User, password: string): Promise { return bcrypt.compare(password, user.password); } - async token(userid: User['id']) { - return this.jwtManager.signSignUpToken(userid); + async hashPassword(password: string) { + return bcrypt.hash(password, 10); } } diff --git a/shared/contracts/admin.contract.ts b/shared/contracts/admin.contract.ts index fa186d00..47b211a1 100644 --- a/shared/contracts/admin.contract.ts +++ b/shared/contracts/admin.contract.ts @@ -5,7 +5,7 @@ import { CreateUserSchema } from "@shared/schemas/users/create-user.schema"; const contract = initContract(); export const adminContract = contract.router({ - createUser: { + addUser: { method: "POST", path: "/admin/users", responses: {