import { PrismaService } from '@/src/core/prisma/prisma.service' import { EnableTotpInput } from '@/src/module/auth/totp/inputs/enable-totp.input' import { BadRequestException, Injectable } from '@nestjs/common' import { User } from '@prisma/generated' import { encode } from 'hi-base32' import { randomBytes } from 'node:crypto' import { TOTP } from 'otpauth' import * as QRCode from 'qrcode' @Injectable() export class TotpService { constructor( private readonly prismaService: PrismaService, ) { } async generate(user: User) { const secret = encode(randomBytes(15)) .replace(/=/g, '') .substring(0, 24) const totp = new TOTP({ issuer: 'TeaStream', label: user.email, algorithm: 'SHA-1', digits: 6, secret, }) const qrcodeUrl = await QRCode.toDataURL(totp.toString()) return { qrcodeUrl, secret, } } async enable(user: User, input: EnableTotpInput) { const { pin, secret } = input const totp = new TOTP({ issuer: 'TeaStream', label: user.email, algorithm: 'SHA-1', digits: 6, secret, }) const delta = totp.validate({ token: pin }) if (delta === null) { throw new BadRequestException('Невереый код') } await this.prismaService.user.update({ where: { id: user.id }, data: { isTotpEnabled: true, totpSecret: secret, }, }) return true } async disable(user: User) { await this.prismaService.user.update({ where: { id: user.id }, data: { isTotpEnabled: false, totpSecret: null, }, }) return true } }