2FA
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
import { Controller, Get, Res, UseGuards, Req } from '@nestjs/common';
|
||||
import { Controller, Get, Res, UseGuards, Req, Post, UnauthorizedException, Body } from '@nestjs/common';
|
||||
import { AuthenticateGuard, FortyTwoAuthGuard } from './guards/42guards';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { Response } from 'express';
|
||||
import { TwoFaDto } from './dto/2fa.dto';
|
||||
import { UsersService } from 'src/users/users.service';
|
||||
import { User } from 'src/users/entities/user.entity';
|
||||
import { request } from 'http';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthenticationController {
|
||||
|
||||
constructor(private authService: AuthenticationService,
|
||||
private userService: UsersService,
|
||||
// private jwtservice: JwtService
|
||||
) {}
|
||||
|
||||
@@ -18,6 +22,7 @@ export class AuthenticationController {
|
||||
@Get()
|
||||
@UseGuards(FortyTwoAuthGuard)
|
||||
login() {
|
||||
console.log('ON EST DANS LOGIN AUTH CONTROLLER');
|
||||
return ;
|
||||
}
|
||||
|
||||
@@ -28,8 +33,8 @@ export class AuthenticationController {
|
||||
*/
|
||||
@Get('redirect')
|
||||
@UseGuards(FortyTwoAuthGuard)
|
||||
async redirect(@Res() response : Response) {
|
||||
response.send(200);
|
||||
async redirect(@Res() response : Response, @Req() request) {
|
||||
response.sendStatus(200);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +53,31 @@ export class AuthenticationController {
|
||||
* Route pour déconnecter l'utilisateur
|
||||
*/
|
||||
@Get('logout')
|
||||
logout() {
|
||||
return 'logout';
|
||||
logout(@Req() request) {
|
||||
console.log('ON EST DANS LOGOUT AUTH CONTROLLER')
|
||||
request.session.destroy();
|
||||
return {msg : 'You are now logged out'};
|
||||
}
|
||||
|
||||
@Post('2fa/generate')
|
||||
@UseGuards(AuthenticateGuard)
|
||||
async register(@Req() request, @Res() response){
|
||||
console.log('ON EST DANS REGISTER POUR 2FA AUTH CONTROLLER')
|
||||
const { otpauth } = await this.authService.generate2FaSecret(request.user);
|
||||
return this.authService.pipeQrCodeStream(response, otpauth);
|
||||
}
|
||||
|
||||
@Post('2fa/turn-on')
|
||||
@UseGuards(AuthenticateGuard)
|
||||
async verify(@Req() request, @Body() {twoFaCode} : TwoFaDto){
|
||||
console.log('ON EST DANS VERIFY POUR 2FA AUTH CONTROLLER')
|
||||
const isCodeIsValid = await this.authService.verify2FaCode(request.user, twoFaCode);
|
||||
if (isCodeIsValid === false)
|
||||
{
|
||||
request.session.destroy();
|
||||
throw new UnauthorizedException('Wrong Code.');
|
||||
}
|
||||
await this.userService.enableTwoFactorAuth(request.user.id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { Friendship } from 'src/friendship/entities/friendship.entity';
|
||||
import { User } from 'src/users/entities/user.entity';
|
||||
@@ -9,7 +7,6 @@ import { UsersService } from 'src/users/users.service';
|
||||
import { AuthenticationController } from './authentication.controller';
|
||||
import { AuthenticationService } from './authentication.service';
|
||||
import { FortyTwoStrategy } from './strategy/42strategy';
|
||||
import { JwtStrategy } from './strategy/jwtStrategy';
|
||||
import { SessionSerializer } from './utils/serializer';
|
||||
|
||||
@Module({
|
||||
|
||||
@@ -2,13 +2,13 @@ import { Injectable } from '@nestjs/common';
|
||||
import { CreateUsersDto } from 'src/users/dto/create-users.dto';
|
||||
import { User } from 'src/users/entities/user.entity';
|
||||
import { UsersService } from 'src/users/users.service';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { toFileStream } from 'qrcode';
|
||||
import { authenticator } from 'otplib';
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationService {
|
||||
constructor(
|
||||
private readonly userService: UsersService,
|
||||
// private readonly jwtService: JwtService,
|
||||
) {}
|
||||
|
||||
async validateUser(createUsersDto :CreateUsersDto){
|
||||
@@ -23,8 +23,21 @@ export class AuthenticationService {
|
||||
return await this.userService.findOneByFourtyTwoId(fourtytwo_id);
|
||||
}
|
||||
|
||||
// async login(payload: any) {
|
||||
// return this.jwtService.sign(payload);
|
||||
// }
|
||||
async verify2FaCode(user : User, code : string) {
|
||||
return authenticator.verify({ token: code, secret: user.secretTwoFactorAuth });
|
||||
}
|
||||
|
||||
async generate2FaSecret(user : User) {
|
||||
const secret = authenticator.generateSecret();
|
||||
const otpauth = authenticator.keyuri(user.email, process.env.TWO_FACTOR_AUTHENTICATION_APP_NAME, secret);
|
||||
await this.userService.setAuthenticatorSecret(user.id, secret);
|
||||
return { secret, otpauth };
|
||||
}
|
||||
|
||||
async pipeQrCodeStream(stream : Response, otpauthUrl : string) {
|
||||
return toFileStream(stream, otpauthUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { IsEmpty, IsString } from "class-validator";
|
||||
|
||||
export class TwoFaDto {
|
||||
@IsString()
|
||||
readonly twoFaCode: string;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
|
||||
import { AuthGuard } from "@nestjs/passport";
|
||||
|
||||
@Injectable()
|
||||
export class JwtAuthGuard extends AuthGuard('jwt') {}
|
||||
|
||||
@@ -18,10 +18,13 @@ export class FortyTwoStrategy extends PassportStrategy(Strategy, "42") {
|
||||
async validate(accessToken: string, refreshToken: string, profile: Profile, callbackURL: string) {
|
||||
console.log("Validate inside strategy.ts");
|
||||
console.log(profile.id, profile.username, profile.phoneNumbers[0].value, profile.emails[0].value, profile.photos[0].value);
|
||||
const userDTO: CreateUsersDto = { fortyTwoId: profile.id, username: profile.username, email: profile.emails[0].value, image_url: profile.photos[0].value };
|
||||
const userDTO: CreateUsersDto = { fortyTwoId: profile.id, username: profile.username, email: profile.emails[0].value, image_url: profile.photos[0].value, isEnabledTwoFactorAuth: false };
|
||||
const user = await this.authenticationService.validateUser(userDTO);
|
||||
if (!user)
|
||||
throw new UnauthorizedException();
|
||||
return user;
|
||||
if (!user.isEnabledTwoFactorAuth)
|
||||
return user;
|
||||
if (userDTO.isEnabledTwoFactorAuth)
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import { Injectable, UnauthorizedException } from "@nestjs/common";
|
||||
import { PassportStrategy } from "@nestjs/passport";
|
||||
import { ExtractJwt, Strategy as PassportJwtStrategy } from "passport-jwt";
|
||||
import { AuthenticationService } from "../authentication.service";
|
||||
import { Request } from "express";
|
||||
|
||||
@Injectable()
|
||||
export class JwtStrategy extends PassportStrategy(PassportJwtStrategy, "jwt") {
|
||||
constructor(private readonly authenticationService: AuthenticationService) {
|
||||
|
||||
super({
|
||||
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
ignoreExpiration: false,
|
||||
secretOrKey: process.env.JWT_SECRET,
|
||||
});
|
||||
}
|
||||
async validate(payload: any) {
|
||||
console.log("Validate inside jwtStrategy.ts");
|
||||
const user = await this.authenticationService.findUser(payload.fourtyTwoId);
|
||||
if (!user)
|
||||
throw new UnauthorizedException('You must be logged in to continue.');
|
||||
return { fourtyTwoId: payload.fourtyTwoId, username: payload.username, image_url: payload.image_url };
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,6 @@ import { Body, Controller, Delete, Get, HttpCode, HttpException, HttpStatus, Par
|
||||
import { AuthenticateGuard } from 'src/auth/42/guards/42guards';
|
||||
import { User } from 'src/users/entities/user.entity';
|
||||
import { CreateFriendshipDto } from './dto/create-friendship.dto';
|
||||
import { UpdateFriendshipDto } from './dto/update-friendship.dto';
|
||||
import { FriendshipStatus } from './entities/friendship.entity';
|
||||
import { FriendshipService } from './friendship.service';
|
||||
|
||||
@Controller('network')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { IsEmail, IsString } from 'class-validator';
|
||||
import { IsBoolean, IsEmail, IsOptional, IsString } from 'class-validator';
|
||||
import { Unique } from 'typeorm';
|
||||
|
||||
export class CreateUsersDto {
|
||||
@@ -10,4 +10,7 @@ export class CreateUsersDto {
|
||||
readonly email: string;
|
||||
@IsString()
|
||||
readonly image_url: string;
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
readonly isEnabledTwoFactorAuth: boolean;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,12 @@ export class User {
|
||||
@Column('json', { nullable: true })
|
||||
status: [string];
|
||||
|
||||
@Column({ default: false, nullable: true })
|
||||
isEnabledTwoFactorAuth: boolean;
|
||||
|
||||
@Column({ nullable: true })
|
||||
secretTwoFactorAuth: string;
|
||||
|
||||
@JoinTable()
|
||||
@OneToMany(type => Friendship , (friendship) => friendship.requesterId)
|
||||
requesterId: Friendship[];
|
||||
|
||||
@@ -73,4 +73,12 @@ export class UsersService {
|
||||
throw new HttpException(`The user could not be deleted.`,HttpStatus.NOT_FOUND);
|
||||
return this.userRepository.remove(user);
|
||||
}
|
||||
|
||||
async enableTwoFactorAuth(id: string) {
|
||||
return this.userRepository.update(id, {isEnabledTwoFactorAuth: true});
|
||||
}
|
||||
|
||||
async setAuthenticatorSecret(id: number, secret: string) {
|
||||
return this.userRepository.update(id, {secretTwoFactorAuth: secret});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user