web-service/apps/auth/src/services/otp.service.ts
2023-06-30 19:47:29 +03:00

88 lines
2.3 KiB
TypeScript

import { InjectRepository } from '@nestjs/typeorm';
import { UserTokenEntity } from '../database/entities/user-token.entity';
import { authenticator as totp } from 'otplib';
import { Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { UserEntity } from '../database/entities/user.entity';
import { UserTokenType, generateString } from '@freeblox/shared';
totp.options = {
window: 2,
};
@Injectable()
export class OTPService {
constructor(
@InjectRepository(UserTokenEntity)
private readonly userTokenRepository: Repository<UserTokenEntity>,
) {}
/**
* Check if the user has TOTP enabled
* @param user User object
* @returns true if the user has TOTP enabled
*/
public async userHasTOTP(user: UserEntity): Promise<boolean> {
return !!(await this.getUserTOTP(user));
}
/**
* Get the TOTP token of a user
* @param user User object
* @returns TOTP token
*/
public async getUserTOTP(user: UserEntity): Promise<UserTokenEntity> {
return this.userTokenRepository.findOne({
where: { user: { id: user.id }, type: UserTokenType.TOTP },
relations: ['user'],
});
}
public validateTOTP(secret: string, token: string): boolean {
return totp.verify({ token, secret });
}
public getTOTPURL(secret: string, username: string): string {
return totp.keyuri(username, 'Freeblox', secret);
}
public createTOTPSecret(): string {
return totp.generateSecret();
}
public async activateTOTP(
user: UserEntity,
secret: string,
): Promise<UserTokenEntity[]> {
const totp = new UserTokenEntity();
const recovery = new UserTokenEntity();
totp.user = user;
totp.token = secret;
totp.type = UserTokenType.TOTP;
recovery.user = user;
recovery.token = Array.from({ length: 8 }, () => generateString(8)).join(
' ',
);
recovery.type = UserTokenType.RECOVERY;
await this.userTokenRepository.save(totp);
await this.userTokenRepository.save(recovery);
return [totp, recovery];
}
public async deactivateTOTP(token: UserTokenEntity): Promise<void> {
if (!token) {
return;
}
await this.userTokenRepository.delete({
type: UserTokenType.RECOVERY,
user: { id: token.user.id },
});
await this.userTokenRepository.remove(token);
}
}