icynet-auth-server/src/modules/objects/user-token/user-totp-token.service.ts

85 lines
2.2 KiB
TypeScript

import { Inject, Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { User } from '../user/user.entity';
import { TokenService } from 'src/modules/utility/services/token.service';
import { authenticator as totp } from 'otplib';
import { UserToken, UserTokenType } from './user-token.entity';
totp.options = {
window: 2,
};
@Injectable()
export class UserTOTPService {
constructor(
@Inject('USER_TOKEN_REPOSITORY')
private userTokenRepository: Repository<UserToken>,
private token: TokenService,
) {}
/**
* Check if the user has TOTP enabled
* @param user User object
* @returns true if the user has TOTP enabled
*/
public async userHasTOTP(user: User): 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: User): Promise<UserToken> {
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, 'Icy Network', secret);
}
public createTOTPSecret(): string {
return totp.generateSecret();
}
public async activateTOTP(user: User, secret: string): Promise<UserToken[]> {
const totp = new UserToken();
const recovery = new UserToken();
totp.user = user;
totp.token = secret;
totp.type = UserTokenType.TOTP;
recovery.user = user;
recovery.token = Array.from({ length: 8 }, () =>
this.token.generateString(8),
).join(' ');
recovery.type = UserTokenType.RECOVERY;
await this.userTokenRepository.save(totp);
await this.userTokenRepository.save(recovery);
return [totp, recovery];
}
public async deactivateTOTP(token: UserToken): Promise<void> {
if (!token) {
return;
}
await this.userTokenRepository.delete({
type: UserTokenType.RECOVERY,
user: { id: token.user.id },
});
await this.userTokenRepository.remove(token);
}
}