70 lines
1.7 KiB
TypeScript
70 lines
1.7 KiB
TypeScript
import { Inject, Injectable } from '@nestjs/common';
|
|
import { Repository } from 'typeorm';
|
|
import { UserTOTPToken } from './user-totp-token.entity';
|
|
import { User } from './user.entity';
|
|
import { TokenService } from 'src/modules/utility/services/token.service';
|
|
import { authenticator as totp } from 'otplib';
|
|
|
|
totp.options = {
|
|
window: 2,
|
|
};
|
|
|
|
@Injectable()
|
|
export class UserTOTPService {
|
|
constructor(
|
|
@Inject('USER_TOTP_TOKEN_REPOSITORY')
|
|
private userTOTPTokenRepository: Repository<UserTOTPToken>,
|
|
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<UserTOTPToken> {
|
|
return this.userTOTPTokenRepository.findOne({
|
|
user,
|
|
activated: true,
|
|
});
|
|
}
|
|
|
|
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<UserTOTPToken> {
|
|
const totp = new UserTOTPToken();
|
|
totp.activated = true;
|
|
totp.user = user;
|
|
totp.token = secret;
|
|
totp.recovery_token = Array.from({ length: 8 }, () =>
|
|
this.token.generateString(8),
|
|
).join(' ');
|
|
|
|
await this.userTOTPTokenRepository.save(totp);
|
|
|
|
return totp;
|
|
}
|
|
}
|