mirror of
https://github.com/Shadowfita/docmost.git
synced 2025-11-19 03:01:10 +10:00
switch to nx monorepo
This commit is contained in:
18
apps/server/src/core/auth/auth.controller.spec.ts
Normal file
18
apps/server/src/core/auth/auth.controller.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AuthController } from './auth.controller';
|
||||
|
||||
describe('AuthController', () => {
|
||||
let controller: AuthController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AuthController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<AuthController>(AuthController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
27
apps/server/src/core/auth/auth.controller.ts
Normal file
27
apps/server/src/core/auth/auth.controller.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Post,
|
||||
} from '@nestjs/common';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { AuthService } from './services/auth.service';
|
||||
import { CreateUserDto } from '../user/dto/create-user.dto';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(private authService: AuthService) {}
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('login')
|
||||
async login(@Body() loginInput: LoginDto) {
|
||||
return await this.authService.login(loginInput);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('register')
|
||||
async register(@Body() createUserDto: CreateUserDto) {
|
||||
return await this.authService.register(createUserDto);
|
||||
}
|
||||
}
|
||||
29
apps/server/src/core/auth/auth.module.ts
Normal file
29
apps/server/src/core/auth/auth.module.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { forwardRef, Module } from '@nestjs/common';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { AuthService } from './services/auth.service';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { EnvironmentService } from '../../environment/environment.service';
|
||||
import { TokenService } from './services/token.service';
|
||||
import { UserModule } from '../user/user.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
JwtModule.registerAsync({
|
||||
useFactory: async (environmentService: EnvironmentService) => {
|
||||
return {
|
||||
global: true,
|
||||
secret: environmentService.getJwtSecret(),
|
||||
signOptions: {
|
||||
expiresIn: environmentService.getJwtTokenExpiresIn(),
|
||||
},
|
||||
};
|
||||
},
|
||||
inject: [EnvironmentService],
|
||||
}),
|
||||
forwardRef(() => UserModule),
|
||||
],
|
||||
controllers: [AuthController],
|
||||
providers: [AuthService, TokenService],
|
||||
exports: [TokenService],
|
||||
})
|
||||
export class AuthModule {}
|
||||
11
apps/server/src/core/auth/dto/login.dto.ts
Normal file
11
apps/server/src/core/auth/dto/login.dto.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class LoginDto {
|
||||
@IsNotEmpty()
|
||||
@IsEmail()
|
||||
email: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
password: string;
|
||||
}
|
||||
4
apps/server/src/core/auth/dto/tokens.dto.ts
Normal file
4
apps/server/src/core/auth/dto/tokens.dto.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface TokensDto {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
}
|
||||
30
apps/server/src/core/auth/guards/JwtGuard.ts
Normal file
30
apps/server/src/core/auth/guards/JwtGuard.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { TokenService } from '../services/token.service';
|
||||
|
||||
@Injectable()
|
||||
export class JwtGuard implements CanActivate {
|
||||
constructor(private tokenService: TokenService) {}
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const token: string = await this.tokenService.extractTokenFromHeader(
|
||||
request,
|
||||
);
|
||||
|
||||
if (!token) {
|
||||
throw new UnauthorizedException('Invalid jwt token');
|
||||
}
|
||||
|
||||
try {
|
||||
request['user'] = await this.tokenService.verifyJwt(token);
|
||||
} catch (error) {
|
||||
throw new UnauthorizedException('Could not verify jwt token');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
18
apps/server/src/core/auth/services/auth.service.spec.ts
Normal file
18
apps/server/src/core/auth/services/auth.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
describe('AuthService', () => {
|
||||
let service: AuthService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [AuthService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<AuthService>(AuthService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
41
apps/server/src/core/auth/services/auth.service.ts
Normal file
41
apps/server/src/core/auth/services/auth.service.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { LoginDto } from '../dto/login.dto';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { CreateUserDto } from '../../user/dto/create-user.dto';
|
||||
import { UserService } from '../../user/user.service';
|
||||
import { TokenService } from './token.service';
|
||||
import { TokensDto } from '../dto/tokens.dto';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
private userService: UserService,
|
||||
private tokenService: TokenService,
|
||||
) {}
|
||||
|
||||
async login(loginDto: LoginDto) {
|
||||
const user: User = await this.userService.findByEmail(loginDto.email);
|
||||
const invalidCredentialsMessage = 'email or password does not match';
|
||||
|
||||
if (
|
||||
!user ||
|
||||
!(await this.userService.compareHash(loginDto.password, user.password))
|
||||
) {
|
||||
throw new UnauthorizedException(invalidCredentialsMessage);
|
||||
}
|
||||
|
||||
user.lastLoginAt = new Date();
|
||||
|
||||
const tokens: TokensDto = await this.tokenService.generateTokens(user);
|
||||
|
||||
return { tokens };
|
||||
}
|
||||
|
||||
async register(createUserDto: CreateUserDto) {
|
||||
const user: User = await this.userService.create(createUserDto);
|
||||
|
||||
const tokens: TokensDto = await this.tokenService.generateTokens(user);
|
||||
|
||||
return { tokens };
|
||||
}
|
||||
}
|
||||
18
apps/server/src/core/auth/services/token.service.spec.ts
Normal file
18
apps/server/src/core/auth/services/token.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { TokenService } from './token.service';
|
||||
|
||||
describe('TokenService', () => {
|
||||
let service: TokenService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [TokenService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<TokenService>(TokenService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
43
apps/server/src/core/auth/services/token.service.ts
Normal file
43
apps/server/src/core/auth/services/token.service.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { EnvironmentService } from '../../../environment/environment.service';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { FastifyRequest } from 'fastify';
|
||||
import { TokensDto } from '../dto/tokens.dto';
|
||||
|
||||
export type JwtPayload = { sub: string; email: string };
|
||||
|
||||
@Injectable()
|
||||
export class TokenService {
|
||||
constructor(
|
||||
private jwtService: JwtService,
|
||||
private environmentService: EnvironmentService,
|
||||
) {}
|
||||
async generateJwt(user: User): Promise<string> {
|
||||
const payload: JwtPayload = {
|
||||
sub: user.id,
|
||||
email: user.email,
|
||||
};
|
||||
return await this.jwtService.signAsync(payload);
|
||||
}
|
||||
|
||||
async generateTokens(user: User): Promise<TokensDto> {
|
||||
return {
|
||||
accessToken: await this.generateJwt(user),
|
||||
refreshToken: null,
|
||||
};
|
||||
}
|
||||
|
||||
async verifyJwt(token: string) {
|
||||
return await this.jwtService.verifyAsync(token, {
|
||||
secret: this.environmentService.getJwtSecret(),
|
||||
});
|
||||
}
|
||||
|
||||
async extractTokenFromHeader(
|
||||
request: FastifyRequest,
|
||||
): Promise<string | undefined> {
|
||||
const [type, token] = request.headers.authorization?.split(' ') ?? [];
|
||||
return type === 'Bearer' ? token : undefined;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user