112 lines
2.8 KiB
TypeScript

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<User>,
@InjectRepository(JWTToken)
protected tokenRepo: Repository<JWTToken>,
protected fsService: FileSystemService
) {}
async getUser(userId: number): Promise<User | null> {
return this.userRepo.findOneBy({
id: userId
});
}
async findUser(username: string, gitlab: boolean): Promise<User | null> {
return this.userRepo.findOneBy({
name: username,
isGitlabUser: gitlab
});
}
async getToken(tokenId: number): Promise<JWTToken | null> {
return this.tokenRepo.findOneBy({
id: tokenId
});
}
async validateUser(username: string, pass: string): Promise<User | null> {
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<void> {
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<User> {
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
});
}
}