fix auth
This commit is contained in:
@@ -4,6 +4,8 @@ import { AppService } from './app.service';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import * as Joi from 'joi';
|
||||
import {UsersModule} from "./users/user.module";
|
||||
import {AuthenticationModule} from "./authentication/authentication.module";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -17,6 +19,7 @@ import * as Joi from 'joi';
|
||||
username: configService.get<string>('POSTGRES_USER'),
|
||||
password: configService.get<string>('POSTGRES_PASSWORD'),
|
||||
database: configService.get<string>('POSTGRES_DB'),
|
||||
autoLoadEntities: true,
|
||||
ssl: {
|
||||
rejectUnauthorized: false, // Needed for Neon and similar managed DBs
|
||||
},
|
||||
@@ -28,7 +31,9 @@ import * as Joi from 'joi';
|
||||
JWT_SECRET: Joi.string().required(),
|
||||
JWT_EXPIRATION_TIME: Joi.string().required(),
|
||||
})
|
||||
})
|
||||
}),
|
||||
UsersModule,
|
||||
AuthenticationModule
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
|
||||
@@ -1,30 +1,31 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
import { AuthenticationController } from './authentication.controller';
|
||||
import { PassportModule } from '@nestjs/passport';
|
||||
import { LocalStrategy } from './local.strategy';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import {Module} from '@nestjs/common';
|
||||
import {AuthenticationService} from './authentication.service';
|
||||
import {AuthenticationController} from './authentication.controller';
|
||||
import {PassportModule} from '@nestjs/passport';
|
||||
import {LocalStrategy} from './local.strategy';
|
||||
import {ConfigModule, ConfigService} from '@nestjs/config';
|
||||
import {JwtModule} from '@nestjs/jwt';
|
||||
import {JwtStrategy} from "./jwt.strategy";
|
||||
import {UsersModule} from "../users/user.module";
|
||||
|
||||
@Module({
|
||||
imports: [UsersModule, PassportModule,
|
||||
imports: [UsersModule, PassportModule,
|
||||
|
||||
ConfigModule,
|
||||
JwtModule.registerAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: (configService: ConfigService) => ({
|
||||
secret: configService.get('JWT_SECRET'),
|
||||
signOptions: {
|
||||
expiresIn: `${configService.get('JWT_EXPIRATION_TIME')}s`,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
ConfigModule,
|
||||
JwtModule.registerAsync({
|
||||
imports: [ConfigModule],
|
||||
inject: [ConfigService],
|
||||
useFactory: (configService: ConfigService) => ({
|
||||
secret: configService.get('JWT_SECRET'),
|
||||
signOptions: {
|
||||
expiresIn: `${configService.get('JWT_EXPIRATION_TIME')}s`,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
|
||||
] as const,
|
||||
providers: [AuthenticationService, LocalStrategy, JwtStrategy] as const,
|
||||
controllers: [AuthenticationController] as const,
|
||||
] as const,
|
||||
providers: [AuthenticationService, LocalStrategy, JwtStrategy] as const,
|
||||
controllers: [AuthenticationController] as const,
|
||||
})
|
||||
export class AuthenticationModule {}
|
||||
export class AuthenticationModule {
|
||||
}
|
||||
@@ -1,121 +1,122 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import {HttpException, HttpStatus, Injectable} from '@nestjs/common';
|
||||
import RegisterDto from './dto/register.dto';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import {JwtService} from '@nestjs/jwt';
|
||||
import {ConfigService} from '@nestjs/config';
|
||||
import {UsersService} from "../users/user.service";
|
||||
import PostgresErrorCode from 'src/database/postgresErrorCodes.enum';
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationService {
|
||||
constructor(
|
||||
private readonly usersService: UsersService,
|
||||
private readonly jwtService: JwtService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
constructor(
|
||||
private readonly usersService: UsersService,
|
||||
private readonly jwtService: JwtService,
|
||||
private readonly configService: ConfigService,
|
||||
) {
|
||||
}
|
||||
|
||||
public async register(registrationData: RegisterDto) {
|
||||
const hashedPassword = await bcrypt.hash(registrationData.password, 10);
|
||||
try {
|
||||
const createdUser = await this.usersService.create({
|
||||
...registrationData,
|
||||
password: hashedPassword,
|
||||
});
|
||||
createdUser.password = undefined;
|
||||
return createdUser;
|
||||
} catch (error) {
|
||||
if (error?.code === PostgresErrorCode.UniqueViolation) {
|
||||
throw new HttpException(
|
||||
'User with that email already exists',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
public async register(registrationData: RegisterDto) {
|
||||
const hashedPassword = await bcrypt.hash(registrationData.password, 10);
|
||||
try {
|
||||
const createdUser = await this.usersService.create({
|
||||
...registrationData,
|
||||
password: hashedPassword,
|
||||
});
|
||||
createdUser.password = undefined;
|
||||
return createdUser;
|
||||
} catch (error) {
|
||||
if (error?.code === PostgresErrorCode.UniqueViolation) {
|
||||
throw new HttpException(
|
||||
'User with that email already exists',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
console.log(error);
|
||||
throw new HttpException(
|
||||
'Something went wrong',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public getCookieWithJwtAccessToken(
|
||||
userId: number,
|
||||
isSecondFactorAuthenticated = false,
|
||||
) {
|
||||
const payload: TokenPayload = {userId, isSecondFactorAuthenticated};
|
||||
const token = this.jwtService.sign(payload, {
|
||||
secret: this.configService.get('JWT_ACCESS_TOKEN_SECRET'),
|
||||
expiresIn: `${this.configService.get(
|
||||
'JWT_ACCESS_TOKEN_EXPIRATION_TIME',
|
||||
)}s`,
|
||||
});
|
||||
return `Authentication=${token}; HttpOnly; Path=/; Max-Age=${this.configService.get(
|
||||
'JWT_ACCESS_TOKEN_EXPIRATION_TIME',
|
||||
)}`;
|
||||
}
|
||||
|
||||
public getCookieWithJwtRefreshToken(userId: number) {
|
||||
const payload: TokenPayload = {userId};
|
||||
const token = this.jwtService.sign(payload, {
|
||||
secret: this.configService.get('JWT_REFRESH_TOKEN_SECRET'),
|
||||
expiresIn: this.configService.get('JWT_ACCESS_TOKEN_EXPIRATION_TIME'),
|
||||
|
||||
});
|
||||
const cookie = `Refresh=${token}; HttpOnly; Path=/; Max-Age=${this.configService.get(
|
||||
'JWT_REFRESH_TOKEN_EXPIRATION_TIME',
|
||||
)}`;
|
||||
return {
|
||||
cookie,
|
||||
token,
|
||||
};
|
||||
}
|
||||
|
||||
public getCookiesForLogOut() {
|
||||
return [
|
||||
'Authentication=; HttpOnly; Path=/; Max-Age=0',
|
||||
'Refresh=; HttpOnly; Path=/; Max-Age=0',
|
||||
];
|
||||
}
|
||||
|
||||
public async getAuthenticatedUser(email: string, plainTextPassword: string) {
|
||||
try {
|
||||
const user = await this.usersService.getByEmail(email);
|
||||
await this.verifyPassword(plainTextPassword, user.password);
|
||||
return user;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'Wrong credentials provided',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async verifyPassword(
|
||||
plainTextPassword: string,
|
||||
hashedPassword: string,
|
||||
) {
|
||||
const isPasswordMatching = await bcrypt.compare(
|
||||
plainTextPassword,
|
||||
hashedPassword,
|
||||
);
|
||||
}
|
||||
throw new HttpException(
|
||||
'Something went wrong',
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
if (!isPasswordMatching) {
|
||||
throw new HttpException(
|
||||
'Wrong credentials provided',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public getCookieWithJwtAccessToken(
|
||||
userId: number,
|
||||
isSecondFactorAuthenticated = false,
|
||||
) {
|
||||
const payload: TokenPayload = { userId, isSecondFactorAuthenticated };
|
||||
const token = this.jwtService.sign(payload, {
|
||||
secret: this.configService.get('JWT_ACCESS_TOKEN_SECRET'),
|
||||
expiresIn: `${this.configService.get(
|
||||
'JWT_ACCESS_TOKEN_EXPIRATION_TIME',
|
||||
)}s`,
|
||||
});
|
||||
return `Authentication=${token}; HttpOnly; Path=/; Max-Age=${this.configService.get(
|
||||
'JWT_ACCESS_TOKEN_EXPIRATION_TIME',
|
||||
)}`;
|
||||
}
|
||||
|
||||
public getCookieWithJwtRefreshToken(userId: number) {
|
||||
const payload: TokenPayload = { userId };
|
||||
const token = this.jwtService.sign(payload, {
|
||||
secret: this.configService.get('JWT_REFRESH_TOKEN_SECRET'),
|
||||
expiresIn: `${this.configService.get(
|
||||
'JWT_REFRESH_TOKEN_EXPIRATION_TIME',
|
||||
)}s`,
|
||||
});
|
||||
const cookie = `Refresh=${token}; HttpOnly; Path=/; Max-Age=${this.configService.get(
|
||||
'JWT_REFRESH_TOKEN_EXPIRATION_TIME',
|
||||
)}`;
|
||||
return {
|
||||
cookie,
|
||||
token,
|
||||
};
|
||||
}
|
||||
|
||||
public getCookiesForLogOut() {
|
||||
return [
|
||||
'Authentication=; HttpOnly; Path=/; Max-Age=0',
|
||||
'Refresh=; HttpOnly; Path=/; Max-Age=0',
|
||||
];
|
||||
}
|
||||
|
||||
public async getAuthenticatedUser(email: string, plainTextPassword: string) {
|
||||
try {
|
||||
const user = await this.usersService.getByEmail(email);
|
||||
await this.verifyPassword(plainTextPassword, user.password);
|
||||
return user;
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
'Wrong credentials provided',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
public async getUserFromAuthenticationToken(token: string) {
|
||||
const payload: TokenPayload = this.jwtService.verify(token, {
|
||||
secret: this.configService.get('JWT_ACCESS_TOKEN_SECRET'),
|
||||
});
|
||||
if (payload.userId) {
|
||||
return this.usersService.getById(payload.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async verifyPassword(
|
||||
plainTextPassword: string,
|
||||
hashedPassword: string,
|
||||
) {
|
||||
const isPasswordMatching = await bcrypt.compare(
|
||||
plainTextPassword,
|
||||
hashedPassword,
|
||||
);
|
||||
if (!isPasswordMatching) {
|
||||
throw new HttpException(
|
||||
'Wrong credentials provided',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
public getCookieForLogOut() {
|
||||
return `Authentication=; HttpOnly; Path=/; Max-Age=0`;
|
||||
}
|
||||
}
|
||||
|
||||
public async getUserFromAuthenticationToken(token: string) {
|
||||
const payload: TokenPayload = this.jwtService.verify(token, {
|
||||
secret: this.configService.get('JWT_ACCESS_TOKEN_SECRET'),
|
||||
});
|
||||
if (payload.userId) {
|
||||
return this.usersService.getById(payload.userId);
|
||||
}
|
||||
}
|
||||
|
||||
public getCookieForLogOut() {
|
||||
return `Authentication=; HttpOnly; Path=/; Max-Age=0`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user