forked from Yara724/api
Fixed mismatched userId on field expert for claim
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
import { Body, Controller, Post } from "@nestjs/common";
|
||||
import { Public } from "./decorators";
|
||||
import { UserLoginDto, UserRegisterDto } from "./dtos";
|
||||
import { AuthService } from "./auth.service";
|
||||
|
||||
@Controller("auth")
|
||||
export class AuthController {
|
||||
constructor(private readonly authService: AuthService) {}
|
||||
|
||||
@Public()
|
||||
@Post("user/register")
|
||||
async register(@Body() userRegisterDto: UserRegisterDto) {
|
||||
return await this.authService.registerUser(userRegisterDto);
|
||||
}
|
||||
|
||||
@Public()
|
||||
@Post("user/login")
|
||||
async login(@Body() userLoginDto: UserLoginDto) {
|
||||
return await this.authService.loginUser(userLoginDto);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { APP_GUARD } from "@nestjs/core";
|
||||
import { JwtModule } from "@nestjs/jwt";
|
||||
import { StringValue } from "ms";
|
||||
import { AuthGuard, RolesGuard } from "./guards";
|
||||
import { AuthController } from "./auth.controller";
|
||||
import { AuthService } from "./auth.service";
|
||||
import { HashService } from "./providers";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
JwtModule.registerAsync({
|
||||
global: true,
|
||||
inject: [ConfigService],
|
||||
useFactory: (configService: ConfigService) => ({
|
||||
secret: configService.get<string>("JWT_SECRET"),
|
||||
signOptions: {
|
||||
expiresIn: configService.get<StringValue>("JWT_EXPIRY"),
|
||||
},
|
||||
}),
|
||||
}),
|
||||
],
|
||||
controllers: [AuthController],
|
||||
providers: [
|
||||
{ provide: APP_GUARD, useClass: AuthGuard },
|
||||
{ provide: APP_GUARD, useClass: RolesGuard },
|
||||
AuthService,
|
||||
HashService,
|
||||
],
|
||||
})
|
||||
export class AuthModule {}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||
import { UserRepository } from "src/features/user/repositories";
|
||||
import { UserLoginDto, UserRegisterDto } from "./dtos";
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(private readonly userRepo: UserRepository) {}
|
||||
|
||||
async registerUser(userRegisterDto: UserRegisterDto) {
|
||||
const user = await this.userRepo.retrieveByCellPhoneNumber(
|
||||
userRegisterDto.cellphoneNumber,
|
||||
);
|
||||
|
||||
if (!user) {
|
||||
// Create user + Send OTP and update database
|
||||
}
|
||||
|
||||
// Send OTP to the cellphone number of user and update database
|
||||
// TODO: Create a mock otp for once we got no otp senders or development phase
|
||||
}
|
||||
|
||||
async loginUser(userLoginDto: UserLoginDto) {
|
||||
const user = await this.userRepo.retrieveByCellPhoneNumber(
|
||||
userLoginDto.cellphoneNumber,
|
||||
);
|
||||
|
||||
if (!user) throw new BadRequestException("User does not exist");
|
||||
|
||||
// Generate token (access + refresh) and save inside the database, return them to the user
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,18 @@
|
||||
import { ScryptOptions } from "node:crypto";
|
||||
|
||||
export const CURRENT_ALGORITHM = "scrypt";
|
||||
export const CURRENT_VERSION = 1; // 0 = legacy salt:hash ; 1 = scrypt with different salt and hash and differnet format of salt:hash!
|
||||
|
||||
export const KEY_LENGTH = 64;
|
||||
export const SCRYPT_PARAMS: ScryptOptions = {
|
||||
N: 19456, // CPU/memory cost
|
||||
r: 8, // block size
|
||||
p: 1, // parallelization
|
||||
};
|
||||
|
||||
export const KEY_LENGTH_FOR_OTP = 32;
|
||||
export const SCRYPT_PARAMS_FOR_OTP: ScryptOptions = {
|
||||
N: 1024,
|
||||
r: 8,
|
||||
p: 1,
|
||||
};
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
export { UserRegisterDto } from "./user-register.dto";
|
||||
export { UserLoginDto } from "./user-login.dto";
|
||||
@@ -1,10 +0,0 @@
|
||||
import { IsMobilePhone, IsNumberString, IsString } from "class-validator";
|
||||
|
||||
export class UserLoginDto {
|
||||
@IsString({ message: "Cellphone number must be string" })
|
||||
@IsMobilePhone("fa-IR")
|
||||
cellphoneNumber: string;
|
||||
|
||||
@IsNumberString()
|
||||
otp: string;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { IsMobilePhone, IsNumberString, IsString } from "class-validator";
|
||||
|
||||
export class UserRegisterDto {
|
||||
@IsString({ message: "Cellphone number must be string" })
|
||||
@IsMobilePhone("fa-IR")
|
||||
cellphoneNumber: string;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import {
|
||||
BinaryLike,
|
||||
randomBytes,
|
||||
scrypt,
|
||||
ScryptOptions,
|
||||
timingSafeEqual,
|
||||
} from "node:crypto";
|
||||
import { promisify } from "node:util";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { KEY_LENGTH, SCRYPT_PARAMS } from "../constants/hash.constants";
|
||||
|
||||
const scryptAsync = promisify<
|
||||
BinaryLike,
|
||||
BinaryLike,
|
||||
number,
|
||||
ScryptOptions,
|
||||
Buffer
|
||||
>(scrypt);
|
||||
|
||||
@Injectable()
|
||||
export class HashService {
|
||||
private readonly pepper: string;
|
||||
|
||||
constructor(private readonly configService: ConfigService) {
|
||||
this.pepper = this.configService.get<string>("HASH_PEPPER");
|
||||
}
|
||||
|
||||
private applyPepper(input: string): string {
|
||||
return this.pepper ? `${input}${this.pepper}` : input;
|
||||
}
|
||||
|
||||
private generateSalt(bytes: number = 16): string {
|
||||
return randomBytes(bytes).toString("hex");
|
||||
}
|
||||
|
||||
private async scrypt(password: string): Promise<[string, string]> {
|
||||
const salt = this.generateSalt();
|
||||
const pepperedInput = this.applyPepper(password);
|
||||
const hashedPassword = await scryptAsync(
|
||||
pepperedInput,
|
||||
salt,
|
||||
KEY_LENGTH,
|
||||
SCRYPT_PARAMS,
|
||||
);
|
||||
|
||||
return [salt, hashedPassword.toString("hex")];
|
||||
}
|
||||
|
||||
private async verifyScrypt(
|
||||
password: string,
|
||||
salt: string,
|
||||
hashedPassword: string,
|
||||
): Promise<boolean> {
|
||||
const pepperedInput = this.applyPepper(password);
|
||||
const derived = await scryptAsync(
|
||||
pepperedInput,
|
||||
salt,
|
||||
KEY_LENGTH,
|
||||
SCRYPT_PARAMS,
|
||||
);
|
||||
const storedBuffer = Buffer.from(hashedPassword, "hex");
|
||||
|
||||
if (derived.length !== storedBuffer.length) return false;
|
||||
|
||||
return timingSafeEqual(derived, storedBuffer);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { HashService } from "./hash.provider";
|
||||
@@ -1 +1,2 @@
|
||||
export { JwtPayload } from "./payload.types";
|
||||
export { PasswordHash } from "./password.types";
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
export interface JwtPayload {
|
||||
sub: string;
|
||||
role: string;
|
||||
clientId?: string;
|
||||
iat?: number;
|
||||
exp?: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user