2024-08-29 23:12:40 +00:00
|
|
|
import { inject, injectable } from "tsyringe";
|
|
|
|
|
import { HMAC } from 'oslo/crypto';
|
2024-08-31 00:36:22 +00:00
|
|
|
import { decodeHex, encodeHex } from 'oslo/encoding';
|
2024-08-29 23:12:40 +00:00
|
|
|
import {CredentialsRepository} from "$lib/server/api/repositories/credentials.repository";
|
2024-08-31 00:36:22 +00:00
|
|
|
import { TOTPController } from "oslo/otp";
|
|
|
|
|
import type { CredentialsType } from "$db/tables";
|
2024-08-29 23:12:40 +00:00
|
|
|
|
|
|
|
|
@injectable()
|
|
|
|
|
export class TotpService {
|
|
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
|
@inject(CredentialsRepository) private readonly credentialsRepository: CredentialsRepository
|
|
|
|
|
) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async findOneByUserId(userId: string) {
|
|
|
|
|
return this.credentialsRepository.findTOTPCredentialsByUserId(userId);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-31 00:36:22 +00:00
|
|
|
async findOneByUserIdOrThrow(userId: string) {
|
|
|
|
|
const credential = await this.findOneByUserId(userId);
|
|
|
|
|
if (!credential) {
|
|
|
|
|
throw new Error('TOTP credential not found');
|
|
|
|
|
}
|
|
|
|
|
return credential;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-29 23:12:40 +00:00
|
|
|
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);
|
|
|
|
|
}
|
2024-08-31 00:36:22 +00:00
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
}
|
2024-08-29 23:12:40 +00:00
|
|
|
}
|