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 { UserRepository } from '@/shared/utils/repositories'
|
||||||
|
|
||||||
import { AuthController } from './auth.controller'
|
import { AuthController } from './auth.controller'
|
||||||
import { AuthRepository } from './auth.repository'
|
|
||||||
import { AuthService } from './auth.service'
|
import { AuthService } from './auth.service'
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [AuthController],
|
controllers: [AuthController],
|
||||||
providers: [
|
providers: [AuthService, UserRepository, OtpService, TokenService]
|
||||||
AuthService,
|
|
||||||
AuthRepository,
|
|
||||||
UserRepository,
|
|
||||||
OtpService,
|
|
||||||
TokenService
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
export class AuthModule {}
|
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 { TokenService } from '../token/token.service'
|
||||||
|
|
||||||
import { AuthRepository } from './auth.repository'
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
public constructor(
|
public constructor(
|
||||||
private readonly authRepository: AuthRepository,
|
|
||||||
private readonly userRepository: UserRepository,
|
private readonly userRepository: UserRepository,
|
||||||
private readonly otpService: OtpService,
|
private readonly otpService: OtpService,
|
||||||
private readonly tokenService: TokenService
|
private readonly tokenService: TokenService
|
||||||
@ -41,7 +38,7 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
account = await this.authRepository.createAccount({
|
account = await this.userRepository.createAccount({
|
||||||
email: isEmailType ? identifier : undefined,
|
email: isEmailType ? identifier : undefined,
|
||||||
phone: isPhoneType ? identifier : undefined
|
phone: isPhoneType ? identifier : undefined
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
import { Controller } from '@nestjs/common'
|
import { Controller } from '@nestjs/common'
|
||||||
import { GrpcMethod } from '@nestjs/microservices'
|
import { GrpcMethod } from '@nestjs/microservices'
|
||||||
import type {
|
import type {
|
||||||
|
TelegramCompleteRequest,
|
||||||
|
TelegramCompleteResponse,
|
||||||
|
TelegramConsumeRequest,
|
||||||
|
TelegramConsumeResponse,
|
||||||
TelegramInitResponse,
|
TelegramInitResponse,
|
||||||
TelegramVerifyRequest,
|
TelegramVerifyRequest,
|
||||||
TelegramVerifyResponse
|
TelegramVerifyResponse
|
||||||
@ -21,4 +25,18 @@ export class TelegramController {
|
|||||||
public verify(data: TelegramVerifyRequest): Promise<TelegramVerifyResponse> {
|
public verify(data: TelegramVerifyRequest): Promise<TelegramVerifyResponse> {
|
||||||
return this.telegramService.verify(data)
|
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 { TelegramRepository } from '@/modules/telegram/telegram.repository'
|
||||||
import { TokenService } from '@/modules/token/token.service'
|
import { TokenService } from '@/modules/token/token.service'
|
||||||
|
import { UserRepository } from '@/shared/utils/repositories'
|
||||||
|
|
||||||
import { TelegramController } from './telegram.controller'
|
import { TelegramController } from './telegram.controller'
|
||||||
import { TelegramService } from './telegram.service'
|
import { TelegramService } from './telegram.service'
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
controllers: [TelegramController],
|
controllers: [TelegramController],
|
||||||
providers: [TelegramService, TelegramRepository, TokenService]
|
providers: [TelegramService, TelegramRepository, TokenService, UserRepository]
|
||||||
})
|
})
|
||||||
export class TelegramModule {}
|
export class TelegramModule {}
|
||||||
|
|||||||
@ -3,6 +3,10 @@ import { ConfigService } from '@nestjs/config'
|
|||||||
import { RpcException } from '@nestjs/microservices'
|
import { RpcException } from '@nestjs/microservices'
|
||||||
import { RpcStatus } from '@teacinema/common'
|
import { RpcStatus } from '@teacinema/common'
|
||||||
import {
|
import {
|
||||||
|
TelegramCompleteRequest,
|
||||||
|
TelegramCompleteResponse,
|
||||||
|
TelegramConsumeRequest,
|
||||||
|
TelegramConsumeResponse,
|
||||||
TelegramInitResponse,
|
TelegramInitResponse,
|
||||||
TelegramVerifyRequest
|
TelegramVerifyRequest
|
||||||
} from '@teacinema/contracts/gen/auth'
|
} from '@teacinema/contracts/gen/auth'
|
||||||
@ -11,6 +15,7 @@ import { createHash, createHmac, randomBytes } from 'node:crypto'
|
|||||||
import { AllConfigs } from '@/config'
|
import { AllConfigs } from '@/config'
|
||||||
import { RedisService } from '@/infra/redis/redis.service'
|
import { RedisService } from '@/infra/redis/redis.service'
|
||||||
import { TokenService } from '@/modules/token/token.service'
|
import { TokenService } from '@/modules/token/token.service'
|
||||||
|
import { UserRepository } from '@/shared/utils/repositories'
|
||||||
|
|
||||||
import { TelegramRepository } from './telegram.repository'
|
import { TelegramRepository } from './telegram.repository'
|
||||||
|
|
||||||
@ -25,7 +30,8 @@ export class TelegramService {
|
|||||||
private readonly redisService: RedisService,
|
private readonly redisService: RedisService,
|
||||||
private readonly configService: ConfigService<AllConfigs>,
|
private readonly configService: ConfigService<AllConfigs>,
|
||||||
private readonly telegramRepository: TelegramRepository,
|
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_ID = configService.get('telegram.telegramBotId', { infer: true })
|
||||||
this.BOT_TOKEN = configService.get('telegram.telegramBotToken', {
|
this.BOT_TOKEN = configService.get('telegram.telegramBotToken', {
|
||||||
@ -94,7 +100,7 @@ export class TelegramService {
|
|||||||
const dataCheckString = dataCheckArr.join('\n')
|
const dataCheckString = dataCheckArr.join('\n')
|
||||||
const secretKey = createHash('sha256')
|
const secretKey = createHash('sha256')
|
||||||
.update(`${this.BOT_ID}:${this.BOT_TOKEN}`)
|
.update(`${this.BOT_ID}:${this.BOT_TOKEN}`)
|
||||||
.digest('hex')
|
.digest()
|
||||||
|
|
||||||
const hmac = createHmac('sha256', secretKey)
|
const hmac = createHmac('sha256', secretKey)
|
||||||
.update(dataCheckString)
|
.update(dataCheckString)
|
||||||
@ -102,4 +108,67 @@ export class TelegramService {
|
|||||||
|
|
||||||
return hmac === hash
|
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 { Injectable } from '@nestjs/common'
|
||||||
import { Account } from '@prisma/generated/client'
|
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'
|
import { PrismaService } from '@/infra/prisma/prisma.service'
|
||||||
|
|
||||||
@ -26,4 +29,8 @@ export class UserRepository {
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public createAccount(data: AccountCreateInput) {
|
||||||
|
return this.prismaService.account.create({ data })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1383,9 +1383,9 @@
|
|||||||
integrity sha512-q3DURJbSk3k8MNWFIYaSM4LEcBgPbWa+HJmBz/nzYT4kuYitJVSXxpZ97kr0Ea+81AZwAU3JhQKlkK0SBWUi0A==
|
integrity sha512-q3DURJbSk3k8MNWFIYaSM4LEcBgPbWa+HJmBz/nzYT4kuYitJVSXxpZ97kr0Ea+81AZwAU3JhQKlkK0SBWUi0A==
|
||||||
|
|
||||||
"@teacinema/contracts@^1.0.0":
|
"@teacinema/contracts@^1.0.0":
|
||||||
version "1.0.8"
|
version "1.0.9"
|
||||||
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.8/contracts-1.0.8.tgz#4e31c3a370b0808629d9c93900c5f27958ef82e6"
|
resolved "https://git.ksv741.keenetic.pro/api/packages/teacinema/npm/%40teacinema%2Fcontracts/-/1.0.9/contracts-1.0.9.tgz#14b136d0c08552147b0de637a7af6d340d538527"
|
||||||
integrity sha512-xyPyifbVwWelgo4MsvhhRl//To+b0Tnp8DtANCzwLBUhwPj3ZG19QgfPB7Ih7PsBU5TD6F80aNlITDxJbFgkFQ==
|
integrity sha512-9BwWvXaDKgRcef6+1ep9vUDWBdOndqheeTX5mXK5OOvLXbLOlzYoqAUoT0ZwaRwOCD+Je/LDrqcdti6eoss71Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@nestjs/microservices" "^11.1.12"
|
"@nestjs/microservices" "^11.1.12"
|
||||||
protoc "33.4.0"
|
protoc "33.4.0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user