boredgame/src/lib/server/api/services/totp.service.ts

54 lines
1.6 KiB
TypeScript

import { CredentialsRepository } from '$lib/server/api/repositories/credentials.repository'
import { HMAC } from 'oslo/crypto'
import { decodeHex, encodeHex } from 'oslo/encoding'
import { TOTPController } from 'oslo/otp'
import { inject, injectable } from 'tsyringe'
import type { CredentialsType } from '../databases/tables'
@injectable()
export class TotpService {
constructor(@inject(CredentialsRepository) private readonly credentialsRepository: CredentialsRepository) {}
async findOneByUserId(userId: string) {
return this.credentialsRepository.findTOTPCredentialsByUserId(userId)
}
async findOneByUserIdOrThrow(userId: string) {
const credential = await this.findOneByUserId(userId)
if (!credential) {
throw new Error('TOTP credential not found')
}
return credential
}
async create(userId: string) {
const twoFactorSecret = await new HMAC('SHA-1').generateKey()
try {
return await this.credentialsRepository.create({
user_id: userId,
secret_data: encodeHex(twoFactorSecret),
type: 'totp',
})
} catch (e) {
console.error(e)
return null
}
}
async deleteOneByUserId(userId: string) {
return this.credentialsRepository.deleteByUserId(userId)
}
async deleteOneByUserIdAndType(userId: string, type: CredentialsType) {
return this.credentialsRepository.deleteByUserIdAndType(userId, type)
}
async verify(userId: string, code: string) {
const credential = await this.credentialsRepository.findTOTPCredentialsByUserId(userId)
if (!credential) {
throw new Error('TOTP credential not found')
}
return await new TOTPController().verify(code, decodeHex(credential.secret_data))
}
}