feat: add telegram authorization
This commit is contained in:
parent
0341b2eafe
commit
0d184020d9
@ -5,17 +5,10 @@ import { TokenService } from '@/modules/token/token.service'
|
||||
import { UserRepository } from '@/shared/utils/repositories'
|
||||
|
||||
import { AuthController } from './auth.controller'
|
||||
import { AuthRepository } from './auth.repository'
|
||||
import { AuthService } from './auth.service'
|
||||
|
||||
@Module({
|
||||
controllers: [AuthController],
|
||||
providers: [
|
||||
AuthService,
|
||||
AuthRepository,
|
||||
UserRepository,
|
||||
OtpService,
|
||||
TokenService
|
||||
]
|
||||
providers: [AuthService, UserRepository, OtpService, TokenService]
|
||||
})
|
||||
export class AuthModule {}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { AccountCreateInput } from '@prisma/generated/models/Account'
|
||||
|
||||
import { PrismaService } from '@/infra/prisma/prisma.service'
|
||||
|
||||
@Injectable()
|
||||
export class AuthRepository {
|
||||
public constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
public createAccount(data: AccountCreateInput) {
|
||||
return this.prismaService.account.create({ data })
|
||||
}
|
||||
}
|
||||
@ -16,12 +16,9 @@ import { UserRepository } from '@/shared/utils/repositories'
|
||||
|
||||
import { TokenService } from '../token/token.service'
|
||||
|
||||
import { AuthRepository } from './auth.repository'
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
public constructor(
|
||||
private readonly authRepository: AuthRepository,
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly otpService: OtpService,
|
||||
private readonly tokenService: TokenService
|
||||
@ -41,7 +38,7 @@ export class AuthService {
|
||||
}
|
||||
|
||||
if (!account) {
|
||||
account = await this.authRepository.createAccount({
|
||||
account = await this.userRepository.createAccount({
|
||||
email: isEmailType ? identifier : undefined,
|
||||
phone: isPhoneType ? identifier : undefined
|
||||
})
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import { Controller } from '@nestjs/common'
|
||||
import { GrpcMethod } from '@nestjs/microservices'
|
||||
import type {
|
||||
TelegramCompleteRequest,
|
||||
TelegramCompleteResponse,
|
||||
TelegramConsumeRequest,
|
||||
TelegramConsumeResponse,
|
||||
TelegramInitResponse,
|
||||
TelegramVerifyRequest,
|
||||
TelegramVerifyResponse
|
||||
@ -21,4 +25,18 @@ export class TelegramController {
|
||||
public verify(data: TelegramVerifyRequest): Promise<TelegramVerifyResponse> {
|
||||
return this.telegramService.verify(data)
|
||||
}
|
||||
|
||||
@GrpcMethod('AuthService', 'TelegramComplete')
|
||||
public complete(
|
||||
data: TelegramCompleteRequest
|
||||
): Promise<TelegramCompleteResponse> {
|
||||
return this.telegramService.complete(data)
|
||||
}
|
||||
|
||||
@GrpcMethod('AuthService', 'TelegramConsume')
|
||||
public consumeSession(
|
||||
data: TelegramConsumeRequest
|
||||
): Promise<TelegramConsumeResponse> {
|
||||
return this.telegramService.consumeSession(data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,12 +2,13 @@ import { Module } from '@nestjs/common'
|
||||
|
||||
import { TelegramRepository } from '@/modules/telegram/telegram.repository'
|
||||
import { TokenService } from '@/modules/token/token.service'
|
||||
import { UserRepository } from '@/shared/utils/repositories'
|
||||
|
||||
import { TelegramController } from './telegram.controller'
|
||||
import { TelegramService } from './telegram.service'
|
||||
|
||||
@Module({
|
||||
controllers: [TelegramController],
|
||||
providers: [TelegramService, TelegramRepository, TokenService]
|
||||
providers: [TelegramService, TelegramRepository, TokenService, UserRepository]
|
||||
})
|
||||
export class TelegramModule {}
|
||||
|
||||
@ -3,6 +3,10 @@ import { ConfigService } from '@nestjs/config'
|
||||
import { RpcException } from '@nestjs/microservices'
|
||||
import { RpcStatus } from '@teacinema/common'
|
||||
import {
|
||||
TelegramCompleteRequest,
|
||||
TelegramCompleteResponse,
|
||||
TelegramConsumeRequest,
|
||||
TelegramConsumeResponse,
|
||||
TelegramInitResponse,
|
||||
TelegramVerifyRequest
|
||||
} from '@teacinema/contracts/gen/auth'
|
||||
@ -11,6 +15,7 @@ import { createHash, createHmac, randomBytes } from 'node:crypto'
|
||||
import { AllConfigs } from '@/config'
|
||||
import { RedisService } from '@/infra/redis/redis.service'
|
||||
import { TokenService } from '@/modules/token/token.service'
|
||||
import { UserRepository } from '@/shared/utils/repositories'
|
||||
|
||||
import { TelegramRepository } from './telegram.repository'
|
||||
|
||||
@ -25,7 +30,8 @@ export class TelegramService {
|
||||
private readonly redisService: RedisService,
|
||||
private readonly configService: ConfigService<AllConfigs>,
|
||||
private readonly telegramRepository: TelegramRepository,
|
||||
private readonly tokenService: TokenService
|
||||
private readonly tokenService: TokenService,
|
||||
private readonly userRepository: UserRepository
|
||||
) {
|
||||
this.BOT_ID = configService.get('telegram.telegramBotId', { infer: true })
|
||||
this.BOT_TOKEN = configService.get('telegram.telegramBotToken', {
|
||||
@ -94,7 +100,7 @@ export class TelegramService {
|
||||
const dataCheckString = dataCheckArr.join('\n')
|
||||
const secretKey = createHash('sha256')
|
||||
.update(`${this.BOT_ID}:${this.BOT_TOKEN}`)
|
||||
.digest('hex')
|
||||
.digest()
|
||||
|
||||
const hmac = createHmac('sha256', secretKey)
|
||||
.update(dataCheckString)
|
||||
@ -102,4 +108,67 @@ export class TelegramService {
|
||||
|
||||
return hmac === hash
|
||||
}
|
||||
|
||||
public async complete(
|
||||
data: TelegramCompleteRequest
|
||||
): Promise<TelegramCompleteResponse> {
|
||||
const { phone, sessionId } = data
|
||||
const raw = await this.redisService.get(`telegram_session:${sessionId}`)
|
||||
|
||||
if (!raw) {
|
||||
throw new RpcException({
|
||||
code: RpcStatus.NOT_FOUND,
|
||||
message: 'Session not found'
|
||||
})
|
||||
}
|
||||
|
||||
const { telegramId }: Record<'telegramId' | 'username', string> =
|
||||
JSON.parse(raw)
|
||||
|
||||
let user = await this.userRepository.findByPhone(phone)
|
||||
|
||||
if (!user) {
|
||||
user = await this.userRepository.createAccount({
|
||||
phone,
|
||||
telegramId
|
||||
})
|
||||
}
|
||||
|
||||
await this.userRepository.updateAccount(user.id, {
|
||||
telegramId,
|
||||
isPhoneVerified: true
|
||||
})
|
||||
|
||||
const tokens = this.tokenService.generateTokens(user.id)
|
||||
|
||||
await this.redisService.set(
|
||||
`telegram_tokens:${sessionId}`,
|
||||
JSON.stringify(tokens),
|
||||
'EX',
|
||||
120
|
||||
)
|
||||
await this.redisService.del(`telegram_session:${sessionId}`)
|
||||
|
||||
return { sessionId }
|
||||
}
|
||||
|
||||
public async consumeSession(
|
||||
data: TelegramConsumeRequest
|
||||
): Promise<TelegramConsumeResponse> {
|
||||
const { sessionId } = data
|
||||
const redisKey = `telegram_tokens:${sessionId}`
|
||||
const raw = await this.redisService.get(redisKey)
|
||||
if (!raw) {
|
||||
throw new RpcException({
|
||||
code: RpcStatus.NOT_FOUND,
|
||||
message: 'Session not found'
|
||||
})
|
||||
}
|
||||
|
||||
const tokens: Record<'accessToken' | 'refreshToken', string> =
|
||||
JSON.parse(raw)
|
||||
await this.redisService.del(redisKey)
|
||||
|
||||
return tokens
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import { Injectable } from '@nestjs/common'
|
||||
import { Account } from '@prisma/generated/client'
|
||||
import { AccountUpdateInput } from '@prisma/generated/models/Account'
|
||||
import {
|
||||
AccountCreateInput,
|
||||
AccountUpdateInput
|
||||
} from '@prisma/generated/models/Account'
|
||||
|
||||
import { PrismaService } from '@/infra/prisma/prisma.service'
|
||||
|
||||
@ -26,4 +29,8 @@ export class UserRepository {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
public createAccount(data: AccountCreateInput) {
|
||||
return this.prismaService.account.create({ data })
|
||||
}
|
||||
}
|
||||
|
||||
@ -1383,9 +1383,9 @@
|
||||
integrity sha512-q3DURJbSk3k8MNWFIYaSM4LEcBgPbWa+HJmBz/nzYT4kuYitJVSXxpZ97kr0Ea+81AZwAU3JhQKlkK0SBWUi0A==
|
||||
|
||||
"@teacinema/contracts@^1.0.0":
|
||||
version "1.0.8"
|
||||
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.8/contracts-1.0.8.tgz#4e31c3a370b0808629d9c93900c5f27958ef82e6"
|
||||
integrity sha512-xyPyifbVwWelgo4MsvhhRl//To+b0Tnp8DtANCzwLBUhwPj3ZG19QgfPB7Ih7PsBU5TD6F80aNlITDxJbFgkFQ==
|
||||
version "1.0.9"
|
||||
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.9/contracts-1.0.9.tgz#14b136d0c08552147b0de637a7af6d340d538527"
|
||||
integrity sha512-9BwWvXaDKgRcef6+1ep9vUDWBdOndqheeTX5mXK5OOvLXbLOlzYoqAUoT0ZwaRwOCD+Je/LDrqcdti6eoss71Q==
|
||||
dependencies:
|
||||
"@nestjs/microservices" "^11.1.12"
|
||||
protoc "33.4.0"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user