Skip to content

Commit

Permalink
Hashing passwords works well | Login and Register well with swagger
Browse files Browse the repository at this point in the history
  • Loading branch information
devbenho committed Jun 14, 2024
1 parent 68081b8 commit a2e2994
Show file tree
Hide file tree
Showing 17 changed files with 206 additions and 201 deletions.
Binary file modified server/db.sqlite3
Binary file not shown.
4 changes: 2 additions & 2 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"description": "Application to manage bugs in a project",
"author": {
"name": "Benho",
"email": "Name",
"url": "url"
"email": "devbenho@gmail.com",
"url": "twitter.com/devbenho"
},

"version": "1.0.0",
Expand Down
13 changes: 13 additions & 0 deletions server/src/application/auth/login/login.use-case.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { UserRepository } from '@domain/entities/users';
import { HasherDomainService } from '@domain/shared/services';
import { TokenProviderDomainService } from '@domain/shared/services/token-provider.domain-service';
import { JwtPayload } from '@contracts/services/IJwt';
import { Logger } from '@domain/shared';

@UseCase()
class LoginUseCase extends BaseUseCase<AuthRequest, AuthResponseDto> {
Expand All @@ -29,6 +30,16 @@ class LoginUseCase extends BaseUseCase<AuthRequest, AuthResponseDto> {
if (!user) {
throw new UnauthorizedError();
}
const isPasswordValid = await HasherDomainService.compare(
await HasherDomainService.hash(request.password),
user.password,
);
Logger.info('user password', user.password);
Logger.info(
'request password',
await HasherDomainService.hash(request.password),
);
Logger.info('Is password valid', isPasswordValid);
if (!(await HasherDomainService.compare(request.password, user.password))) {
throw new UnauthorizedError();
}
Expand All @@ -41,12 +52,14 @@ class LoginUseCase extends BaseUseCase<AuthRequest, AuthResponseDto> {
};

const token = this._jwtService.createAccessToken(payload);
Logger.info('Token created', token);
const result: AuthResponseDto = {
token,
// tokenExpiration type is Date
tokenExpiration: new Date(),
userDetails: user,
};
Logger.info('Result', result);
return result;
}
}
Expand Down
79 changes: 49 additions & 30 deletions server/src/application/auth/register/register.use-case.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,52 @@
// import 'reflect-metadata';
// import { AuthResponseDto } from '@contracts/dtos/auth';
// import { CreateUserDto } from '@contracts/dtos/users';
// import { TYPES } from '@infrastructure/shared/ioc/types';
// import { inject, injectable } from 'inversify';
// import { BaseUseCase } from '@application/shared';
// import { UserRepository } from '@domain/repositories/user.repository';
// import { log } from 'console';
// import { TokenProviderDomainService } from '@domain/shared/services/token-provider.domain-service';
import 'reflect-metadata';
import { AuthResponseDto } from '@contracts/dtos/auth';
import { CreateUserDto } from '@contracts/dtos/users';
import { BaseUseCase, UseCase } from '@application/shared';
import { TokenProviderDomainService } from '@domain/shared/services/token-provider.domain-service';
import { UserRepository } from '@domain/entities';
import { JwtPayload } from '@contracts/services/IJwt';
import { HasherDomainService } from '@domain/shared/services';
import { Hash } from 'crypto';

// @injectable()
// class RegisterUsecase extends BaseUseCase<CreateUserDto, AuthResponseDto> {
// private _userRepository: UserRepository,
// private _jwtService: TokenProviderDomainService,
@UseCase()
class RegisterUsecase extends BaseUseCase<CreateUserDto, AuthResponseDto> {
private _userRepository: UserRepository;
private _jwtService: TokenProviderDomainService;
private _hasherService: HasherDomainService;

// public async performOperation(
// request: CreateUserDto,
// ): Promise<AuthResponseDto> {
// const user = request.toEntity();
// const createdUser = await this._userRepository.saveUser(user);
// log('createdUser', createdUser);
// const result: AuthResponseDto = {
// token: this._jwtService.({ userId: createdUser.id as string }),
// tokenExpiration: new Date(Date.now() + 1000 * 60 * 60),
// // refreshToken: this._jwtService.sign({ userId: createdUser.id as string }),
// // refreshTokenExpiration: new Date(Date.now() + 1000 * 60 * 60 * 24),
// userDetails: createdUser,
// };
// return result;
// }
// }
constructor(
userRepository: UserRepository,
jwtService: TokenProviderDomainService,
hasherService: HasherDomainService,
) {
super();
this._userRepository = userRepository;
this._jwtService = jwtService;
this._hasherService = hasherService;
}

// export { RegisterUsecase };
public async performOperation(
request: CreateUserDto,
): Promise<AuthResponseDto> {
const user = request.toEntity();
user.password = await HasherDomainService.hash(user.password);
const createdUser = await this._userRepository.saveUser(user);
const payload = {
email: { value: user.email },
roles: user.roles.map(role => ({ value: role })),
username: { value: user.username },
userUuid: { value: user.id as string },
} as JwtPayload;

const token = this._jwtService.createAccessToken(payload);

const result: AuthResponseDto = {
token,
tokenExpiration: new Date(Date.now() + 1000 * 60 * 60),
userDetails: createdUser,
};
return result;
}
}

export { RegisterUsecase };
6 changes: 3 additions & 3 deletions server/src/infrastructure/comments/comment.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ export class CommentMapper {
}

if (comment.replies) {
commentPersistence.replies = Promise.all(
comment.replies.map(reply => ReplyMapper.toPersistence(reply)),
);
// commentPersistence.replies = Promise.all(
// comment.replies.map(reply => ReplyMapper.toPersistence(reply)),
// );
}

if (comment.likes) {
Expand Down
37 changes: 23 additions & 14 deletions server/src/infrastructure/replies/reply.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ class ReplyMapper {
likes?: LikeReplyPersistence[];
},
): Reply {
const comment = (lazyEntities?.comment ?? null) as Nullable<Comment>;
const user = (lazyEntities?.user ?? null) as Nullable<User>;
const likes = lazyEntities?.likes
const domainComment = (lazyEntities?.comment ?? null) as Nullable<Comment>;
const domainUser = (lazyEntities?.user ?? null) as Nullable<User>;
const domainLikes = lazyEntities?.likes
? lazyEntities.likes.map(like => LikeReplyMapper.toDomain(like))
: [];

return new Reply(
reply.id,
reply.commentId,
comment,
domainComment,
reply.userId,
user,
domainUser,
reply.content,
likes,
domainLikes,
reply.createdAt,
reply.userId,
reply.updatedAt,
Expand All @@ -40,7 +40,7 @@ class ReplyMapper {
);
}

static async toPersistence(reply: Reply): Promise<ReplyPersistence> {
static toPersistence(reply: Reply): ReplyPersistence {
const replyPersistence = new ReplyPersistence();

if (reply.id != null) {
Expand All @@ -51,13 +51,22 @@ class ReplyMapper {
replyPersistence.content = reply.content;
replyPersistence.createdAt = reply.createdAt;
replyPersistence.deletedAt = reply.deletedAt;
replyPersistence.comment = await CommentMapper.toPersistence(
reply.comment as Comment,
);
replyPersistence.user = await UserMapper.toPersistence(reply.user as User);
replyPersistence.likes = await Promise.all(
(reply.likes ?? []).map(like => LikeReplyMapper.toPersistence(like)),
);
if (reply.comment) {
replyPersistence.comment = Promise.resolve(
CommentMapper.toPersistence(reply.comment),
);
}
if (reply.user) {
replyPersistence.user = Promise.resolve(
UserMapper.toPersistence(reply.user),
);
}

if (reply.likes) {
replyPersistence.likes = Promise.all(
reply.likes.map(like => LikeReplyMapper.toPersistence(like)),
);
}

return replyPersistence;
}
Expand Down
15 changes: 10 additions & 5 deletions server/src/infrastructure/replies/reply.persistence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import {
CreateDateColumn,
DeleteDateColumn,
Entity,
JoinTable,
ManyToOne,
OneToMany,
OneToOne,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from 'typeorm';
Expand Down Expand Up @@ -37,14 +37,19 @@ class ReplyPersistence {
@Column()
commentId: string;

@ManyToOne(() => CommentPersistence, comment => comment.replies, { lazy: true })
comment: CommentPersistence;
@ManyToOne(() => CommentPersistence, comment => comment.replies, {
lazy: true,
})
@JoinTable()
comment: Promise<CommentPersistence>;

@ManyToOne(() => UserPersistence, user => user.replies, { lazy: true })
user: UserPersistence;
@JoinTable()
user: Promise<UserPersistence>;

@OneToMany(() => LikeReplyPersistence, like => like.reply, { lazy: true })
likes: LikeReplyPersistence[];
@JoinTable()
likes: Promise<LikeReplyPersistence[]>;
}

export { ReplyPersistence };
3 changes: 2 additions & 1 deletion server/src/infrastructure/replies/reply.repository.imp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { DataSource, Repository } from 'typeorm';
@injectable()
export class ReplyRepository
extends Repository<Reply>
implements IReplyRepository {
implements IReplyRepository
{
constructor(dataSource: DataSource) {
super(Reply, dataSource.createEntityManager());
}
Expand Down
2 changes: 2 additions & 0 deletions server/src/infrastructure/shared/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Logger } from '@domain/shared';

// import { Cache } from './cache/cache';
import { DependencyInjection } from './di/dependency-injection';
import { appDataSource } from './persistence/data-source';

interface BootstrapResult {
bootstrapDuration: number;
Expand All @@ -23,6 +24,7 @@ const bootstrap = async (): Promise<BootstrapResult> => {
Logger.info(decorateLoggerMessage('Initializing DI container...'));

await DependencyInjection.initialize();
await appDataSource.initialize(); // Initialize the database connection

Logger.info(decorateLoggerMessage('DI container initialized!'));

Expand Down
18 changes: 0 additions & 18 deletions server/src/infrastructure/shared/hasher/hasher.service.ts
Original file line number Diff line number Diff line change
@@ -1,18 +0,0 @@
import bcrypt from 'bcrypt';
import { IHasherService } from '@contracts/services/IHasher';
import { injectable } from 'inversify';

@injectable()
class HasherService implements IHasherService {
private readonly saltRounds = 10;

async hash(password: string): Promise<string> {
return bcrypt.hash(password, this.saltRounds);
}

async compare(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash);
}
}

export { HasherService };
88 changes: 44 additions & 44 deletions server/src/infrastructure/shared/ioc/inversify.config.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,44 @@
import 'reflect-metadata';
import { Container } from 'inversify';
import { TYPES } from './types';
import { JwtService } from '@infrastructure/shared/jwt/jwt.service.impl';
import { UserMapper, UserRepository } from '@infrastructure/users';

import { HasherService } from '@infrastructure/shared/hasher/hasher.service';
import { AuthController } from '@/web/rest/controllers';
import { LoginUseCase } from '@application/auth/login/login.use-case';
import { RegisterUsecase } from '@application/auth/register/register.use-case';
import { DataSource } from 'typeorm';
import { appDataSource } from '@infrastructure/shared/persistence/data-source';
import { PostsController } from '@/web/rest/controllers/posts.controller';
import { PostRepositoryImp } from '@infrastructure/posts';
import { CreatePostUseCase } from '@application/post';
import { FindAllPostUseCase } from '@application/post/find-all/find-all-post.usecase';

const container = new Container();
// Bind the extrernal dependencies
container.bind(TYPES.IJwtService).to(JwtService);
container.bind(TYPES.IHasherService).to(HasherService);
container.bind(TYPES.IUserMapper).to(UserMapper);

// Inject the repositories
container.bind(TYPES.IUserRepository).to(UserRepository);
container.bind(TYPES.IPostRepository).to(PostRepositoryImp);

// Inject input ports
container.bind(TYPES.ILoginInputPort).to(LoginUseCase);
container.bind(TYPES.IRegisterInputPort).to(RegisterUsecase);

container.bind(TYPES.ICreatePostInputPort).to(CreatePostUseCase);
container.bind(TYPES.IFindAllPostInputPort).to(FindAllPostUseCase);

// Bind the controllers
container.bind(TYPES.IAuthController).to(AuthController);
container.bind(TYPES.IPostController).to(PostsController);

// Bind ApplicationRouter

// bind the datastore
container.bind<DataSource>(DataSource).toConstantValue(appDataSource);

export { container };
// import 'reflect-metadata';
// import { Container } from 'inversify';
// import { TYPES } from './types';
// import { JwtService } from '@infrastructure/shared/jwt/jwt.service.impl';
// import { UserMapper, UserRepository } from '@infrastructure/users';

// import { HasherService } from '@infrastructure/shared/hasher/hasher.service';
// import { AuthController } from '@/web/rest/controllers';
// import { LoginUseCase } from '@application/auth/login/login.use-case';
// import { RegisterUsecase } from '@application/auth/register/register.use-case';
// import { DataSource } from 'typeorm';
// import { appDataSource } from '@infrastructure/shared/persistence/data-source';
// import { PostsController } from '@/web/rest/controllers/posts.controller';
// import { PostRepositoryImp } from '@infrastructure/posts';
// import { CreatePostUseCase } from '@application/post';
// import { FindAllPostUseCase } from '@application/post/find-all/find-all-post.usecase';

// const container = new Container();
// // Bind the extrernal dependencies
// container.bind(TYPES.IJwtService).to(JwtService);
// container.bind(TYPES.IHasherService).to(HasherService);
// container.bind(TYPES.IUserMapper).to(UserMapper);

// // Inject the repositories
// container.bind(TYPES.IUserRepository).to(UserRepository);
// container.bind(TYPES.IPostRepository).to(PostRepositoryImp);

// // Inject input ports
// container.bind(TYPES.ILoginInputPort).to(LoginUseCase);
// container.bind(TYPES.IRegisterInputPort).to(RegisterUsecase);

// container.bind(TYPES.ICreatePostInputPort).to(CreatePostUseCase);
// container.bind(TYPES.IFindAllPostInputPort).to(FindAllPostUseCase);

// // Bind the controllers
// container.bind(TYPES.IAuthController).to(AuthController);
// container.bind(TYPES.IPostController).to(PostsController);

// // Bind ApplicationRouter

// // bind the datastore
// container.bind<DataSource>(DataSource).toConstantValue(appDataSource);

// export { container };
Loading

0 comments on commit a2e2994

Please sign in to comment.