From 2b5abc7689a834b183357ac9cdab7888ec7715e8 Mon Sep 17 00:00:00 2001 From: ilham Date: Mon, 6 Dec 2021 09:12:52 +0700 Subject: [PATCH] add: progress authentication --- package.json | 3 ++ src/app.module.ts | 2 + src/auth/dto/input-login.dto.ts | 9 +++++ src/auth/dto/response-login.dto.ts | 9 +++++ src/configurable/configurable.controller.ts | 6 +-- src/configurable/configurable.service.ts | 10 ++++- src/helper/hash_password.ts | 10 +++++ src/helper/jwt.strategy.ts | 22 +++++++++++ .../entities/coa.entity.ts | 10 ++--- .../entities/transaction.entity.ts | 39 ++++++++++++++++++- .../entities/transaction_journal.entity.ts | 36 +++++++++++++++++ src/users/entities/user.entity.ts | 38 +++++------------- 12 files changed, 154 insertions(+), 40 deletions(-) create mode 100644 src/auth/dto/input-login.dto.ts create mode 100644 src/auth/dto/response-login.dto.ts create mode 100644 src/helper/hash_password.ts create mode 100644 src/helper/jwt.strategy.ts rename src/{ledger => transaction}/entities/coa.entity.ts (81%) create mode 100644 src/transaction/entities/transaction_journal.entity.ts diff --git a/package.json b/package.json index 637bced..105e35a 100644 --- a/package.json +++ b/package.json @@ -25,13 +25,16 @@ "@nestjs/config": "^1.0.1", "@nestjs/core": "^8.0.0", "@nestjs/mapped-types": "*", + "@nestjs/passport": "^8.0.1", "@nestjs/platform-express": "^8.0.0", "@nestjs/platform-fastify": "^8.0.8", "@nestjs/typeorm": "^8.0.2", "class-transformer": "^0.4.0", "class-validator": "^0.13.1", + "crypto": "^1.0.1", "joi": "^17.4.2", "nestjs-pino": "^2.3.1", + "passport-jwt": "^4.0.0", "pg": "^8.7.1", "pino-http": "^6.3.0", "reflect-metadata": "^0.1.13", diff --git a/src/app.module.ts b/src/app.module.ts index 25df6d3..3bc5761 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -8,6 +8,7 @@ import { LoggerModule } from 'nestjs-pino'; import { TransactionModule } from './transaction/transaction.module'; import { ProductModule } from './product/product.module'; import { ConfigurableModule } from './configurable/configurable.module'; +import { AuthModule } from './auth/auth.module'; import configuration from './config/configuration'; @Module({ @@ -50,6 +51,7 @@ import configuration from './config/configuration'; UsersModule, TransactionModule, ConfigurableModule, + AuthModule, // ProductModule, ], }) diff --git a/src/auth/dto/input-login.dto.ts b/src/auth/dto/input-login.dto.ts new file mode 100644 index 0000000..813ba07 --- /dev/null +++ b/src/auth/dto/input-login.dto.ts @@ -0,0 +1,9 @@ +import { IsNotEmpty } from 'class-validator'; + +export class InputLoginDto { + @IsNotEmpty() + username: string; + + @IsNotEmpty() + password: string; +} diff --git a/src/auth/dto/response-login.dto.ts b/src/auth/dto/response-login.dto.ts new file mode 100644 index 0000000..3132636 --- /dev/null +++ b/src/auth/dto/response-login.dto.ts @@ -0,0 +1,9 @@ +import { IsNotEmpty } from 'class-validator'; + +export class ResponseLoginDto { + @IsNotEmpty() + username: string; + + @IsNotEmpty() + jwt: string; +} diff --git a/src/configurable/configurable.controller.ts b/src/configurable/configurable.controller.ts index d1c99e6..21d4c01 100644 --- a/src/configurable/configurable.controller.ts +++ b/src/configurable/configurable.controller.ts @@ -7,7 +7,7 @@ import { Param, Delete, ParseUUIDPipe, - HttpStatus, + HttpStatus, Query, } from '@nestjs/common'; import { ConfigurableService } from './configurable.service'; @@ -19,8 +19,8 @@ export class ConfigurableController { constructor(private readonly usersService: ConfigurableService) {} @Get() - async findAll() { - const [data, count] = await this.usersService.findAll(); + async findAll(@Query('page') page: number) { + const [data, count] = await this.usersService.findAllRoles(page); return { data, diff --git a/src/configurable/configurable.service.ts b/src/configurable/configurable.service.ts index 5236a1b..109c824 100644 --- a/src/configurable/configurable.service.ts +++ b/src/configurable/configurable.service.ts @@ -10,8 +10,14 @@ export class ConfigurableService { private rolesRepository: Repository, ) {} - findAll() { - return this.rolesRepository.findAndCount(); + findAllRoles(page) { + return this.rolesRepository.findAndCount({ + skip: page * 10, + take: 10, + order: { + version: 'DESC', + }, + }); } async findOne(id: string) { diff --git a/src/helper/hash_password.ts b/src/helper/hash_password.ts new file mode 100644 index 0000000..1575fd6 --- /dev/null +++ b/src/helper/hash_password.ts @@ -0,0 +1,10 @@ +import * as crypto from 'crypto'; + +export function hashPassword(password, salt): Promise { + return new Promise((resolve, reject) => { + crypto.pbkdf2(password, salt, 50, 100, 'sha512', (err, values) => { + if (err) return reject(err); + resolve(values.toString('hex')); + }); + }); +} diff --git a/src/helper/jwt.strategy.ts b/src/helper/jwt.strategy.ts new file mode 100644 index 0000000..c5d278e --- /dev/null +++ b/src/helper/jwt.strategy.ts @@ -0,0 +1,22 @@ +import { PassportStrategy } from '@nestjs/passport'; +import { ExtractJwt, Strategy } from 'passport-jwt'; +import { Injectable } from '@nestjs/common'; +import { AuthService } from '../auth/auth.service'; + +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy) { + constructor(private readonly authService: AuthService) { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: process.env.SECRETKEY, + }); + } + + async validate(payload: JwtPayload): Promise { + const user = await this.authService.validateUser(payload); + if (!user) { + throw new HttpException('Invalid token', HttpStatus.UNAUTHORIZED); + } + return user; + } +} \ No newline at end of file diff --git a/src/ledger/entities/coa.entity.ts b/src/transaction/entities/coa.entity.ts similarity index 81% rename from src/ledger/entities/coa.entity.ts rename to src/transaction/entities/coa.entity.ts index a4dbaa0..cd95f70 100644 --- a/src/ledger/entities/coa.entity.ts +++ b/src/transaction/entities/coa.entity.ts @@ -5,7 +5,10 @@ import { UpdateDateColumn, DeleteDateColumn, VersionColumn, - CreateDateColumn, ManyToOne, ManyToMany, JoinTable, + CreateDateColumn, + ManyToOne, + ManyToMany, + JoinTable, } from 'typeorm'; import { Product } from '../../product/entities/product.entity'; import { User } from '../../users/entities/user.entity'; @@ -22,10 +25,7 @@ enum balanceType { } @Entity() -export class Roles extends BaseModel{ - @PrimaryGeneratedColumn('uuid') - id: string; - +export class COA extends BaseModel { @Column() name: string; diff --git a/src/transaction/entities/transaction.entity.ts b/src/transaction/entities/transaction.entity.ts index 9d16154..4cf5e85 100644 --- a/src/transaction/entities/transaction.entity.ts +++ b/src/transaction/entities/transaction.entity.ts @@ -1 +1,38 @@ -export class Transaction {} +import { + Entity, + Column, + PrimaryGeneratedColumn, + UpdateDateColumn, + DeleteDateColumn, + VersionColumn, + CreateDateColumn, + ManyToOne, + ManyToMany, + JoinTable, +} from 'typeorm'; +import { Product } from '../../product/entities/product.entity'; +import { User } from '../../users/entities/user.entity'; +import { BaseModel } from '../../config/basemodel.entity'; +import { COA } from './coa.entity'; +import { ProductHistoryPrice } from '../../product/entities/product-history-price.entity'; + +enum status { + PENDING, + SUCCESS, + FAILED, +} + +@Entity() +export class Transaction extends BaseModel { + @Column() + amount: number; + + @Column() + status: status; + + @ManyToOne(() => User, (user) => user.id) + user: User; + + @ManyToOne(() => ProductHistoryPrice, (productHistory) => productHistory.id) + product: ProductHistoryPrice; +} diff --git a/src/transaction/entities/transaction_journal.entity.ts b/src/transaction/entities/transaction_journal.entity.ts new file mode 100644 index 0000000..1333950 --- /dev/null +++ b/src/transaction/entities/transaction_journal.entity.ts @@ -0,0 +1,36 @@ +import { + Entity, + Column, + PrimaryGeneratedColumn, + UpdateDateColumn, + DeleteDateColumn, + VersionColumn, + CreateDateColumn, ManyToOne, ManyToMany, JoinTable, +} from 'typeorm'; +import { Product } from '../../product/entities/product.entity'; +import { User } from '../../users/entities/user.entity'; +import { BaseModel } from '../../config/basemodel.entity'; +import { ProductCategories } from '../../product/entities/product-category.entity'; +import { COA } from './coa.entity'; + +enum type { + SYSTEM_BANk, + INCOME, +} + +enum balanceType { + DEBIT, + CREDIT, +} + +@Entity() +export class TransactionJournal extends BaseModel { + @Column('text') + type: type; + + @Column() + amount: number; + + @ManyToOne(() => COA, (coa) => coa.id) + coa: COA; +} diff --git a/src/users/entities/user.entity.ts b/src/users/entities/user.entity.ts index 417e96f..723e4a9 100644 --- a/src/users/entities/user.entity.ts +++ b/src/users/entities/user.entity.ts @@ -1,45 +1,25 @@ import { Entity, Column, - PrimaryGeneratedColumn, - UpdateDateColumn, - DeleteDateColumn, - VersionColumn, - CreateDateColumn, + PrimaryGeneratedColumn, BeforeInsert, } from 'typeorm'; +import { BaseModel } from '../../config/basemodel.entity'; +import { hashPassword } from '../../helper/hash_password'; @Entity() -export class User { +export class User extends BaseModel { @PrimaryGeneratedColumn('uuid') id: string; @Column() - firstName: string; + username: string; @Column() - lastName: string; + password: string; + + @Column() + salt: string; @Column({ default: true }) isActive: boolean; - - @CreateDateColumn({ - type: 'timestamp with time zone', - nullable: false, - }) - createdAt: Date; - - @UpdateDateColumn({ - type: 'timestamp with time zone', - nullable: false, - }) - updatedAt: Date; - - @DeleteDateColumn({ - type: 'timestamp with time zone', - nullable: true, - }) - deletedAt: Date; - - @VersionColumn() - version: number; }