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

72 lines
1.9 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, type: UserTokenType.TOTP },
});
}
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];
}
}