auth-service/src/modules/otp/otp.service.ts

60 lines
1.5 KiB
TypeScript

import { Injectable } from '@nestjs/common'
import { RpcException } from '@nestjs/microservices'
import { RpcStatus } from '@teacinema/common'
import { createHash } from 'node:crypto'
import { RedisService } from '@/infra/redis/redis.service'
@Injectable()
export class OtpService {
public constructor(private readonly redisService: RedisService) {}
public async send(indentifier: string, type: 'email' | 'phone') {
const { code, hash } = this.generateCode()
await this.redisService.set(
`otp:${type}:${indentifier}`,
hash,
'EX',
60 * 5
)
return code
}
public async verify(
indentifier: string,
code: string,
type: 'email' | 'phone'
) {
const stroredHash = await this.redisService.get(
`otp:${type}:${indentifier}`
)
if (!stroredHash) {
throw new RpcException({
code: RpcStatus.NOT_FOUND,
details: 'Invalid or expired code'
})
}
const hash = createHash('sha256').update(code).digest('hex')
if (stroredHash !== hash) {
throw new RpcException({
code: RpcStatus.NOT_FOUND,
details: 'Invalid or expired code'
})
}
await this.redisService.del(`otp:${type}:${indentifier}`)
}
private generateCode() {
// todo посмотреть готовые бибилотеки для генерации friendly otp
const code = Math.floor(100_000 + Math.random() * 900_000)
const hash = createHash('sha256').update(String(code)).digest('hex')
return { code, hash }
}
}