2025-07-05 09:47:38 +03:00

78 lines
1.6 KiB
TypeScript

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
}
}