import { BadRequestException, Injectable, UnauthorizedException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { JWTToken, User, UserRole } from '../../entities'; import { LessThanOrEqual, Repository } from 'typeorm'; import * as argon2 from 'argon2'; import FileSystemService from '../filesystem'; import * as jwt from 'jsonwebtoken'; export const jwtSecret = 'CUM'; export interface jwtPayload { sub: number; jti: number; exp?: number; iat?: number; } @Injectable() export default class BaseAuthService { constructor( @InjectRepository(User) protected userRepo: Repository, @InjectRepository(JWTToken) protected tokenRepo: Repository, protected fsService: FileSystemService ) {} async getUser(userId: number): Promise { return this.userRepo.findOneBy({ id: userId }); } async findUser(username: string, gitlab: boolean): Promise { return this.userRepo.findOneBy({ name: username, isGitlabUser: gitlab }); } async getToken(tokenId: number): Promise { return this.tokenRepo.findOneBy({ id: tokenId }); } async validateUser(username: string, pass: string): Promise { const user = await this.findUser(username, false); if (!user) throw new UnauthorizedException('Invalid username or password'); if (!(await argon2.verify(user.password, pass))) throw new UnauthorizedException('Invalid username or password'); if (user.role == UserRole.DISABLED) throw new UnauthorizedException('Account is disabled'); return user; } async cleanupTokens(): Promise { await this.tokenRepo.delete({ exp: LessThanOrEqual(Math.floor(Date.now() / 1000)) }); } async login(req: Request, user: User) { const token = new JWTToken(); token.ownerId = user.id; const db_token = await this.tokenRepo.save(token); const payload: jwtPayload = { sub: user.id, jti: db_token.id }; const jwtToken = jwt.sign(payload, jwtSecret, { mutatePayload: true, expiresIn: '1d' }); db_token.exp = payload.exp; await this.tokenRepo.save(db_token); return jwtToken; } async singupInternal(user: User): Promise { const root = await this.fsService.generateRoot(user); user.rootId = root.id; return this.userRepo.save(user); } async signup(username: string, password: string) { if (await this.findUser(username, false)) throw new BadRequestException('User already exists'); const user = new User(); user.name = username; user.password = await argon2.hash(password); await this.singupInternal(await this.userRepo.save(user)); } async revoke(token: JWTToken) { await this.tokenRepo.delete({ id: token.id }); } async revokeAll(user: User) { await this.tokenRepo.delete({ ownerId: user.id }); } }