import axios from 'axios'; import { Queue } from 'bull'; import * as admin from 'firebase-admin'; import { Repository } from 'typeorm'; import { InjectQueue } from '@nestjs/bull'; import { BadRequestException, Inject, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { User } from './database/entities'; import { QuestType } from './funki-id.dto'; import { FunkiXConfiguration } from './funki-id.module'; @Injectable() export class FunkiIdXService { constructor( @InjectRepository(User, 'funki-id') private readonly userRepo: Repository, @Inject('FIREBASE_AUTH') private readonly firebaseAuth: admin.auth.Auth, @InjectQueue('validate-quest-by-type-queue') private readonly validateQueue: Queue, @Inject('X_CONFIG') private readonly xConfig: FunkiXConfiguration, ) {} private getAges(xId: string): number { const creationDate = new Date(parseInt(xId) / 4194304 + 1288834974657); const now = new Date(); const ageInMilliseconds = now.getTime() - creationDate.getTime(); return Math.floor(ageInMilliseconds / (365.25 * 24 * 60 * 60 * 1000) + 0.5); } public async findOrCreateUserByXInfo(userData?: User) { if (!userData?.uid) throw new BadRequestException('Invalid funkiId'); const xUser = await this.firebaseAuth.getUser(userData.uid); if (!xUser) throw new BadRequestException('Invalid request link X account'); const xId = xUser.providerData?.find(p => p.providerId === 'twitter.com')?.uid; if (!xId) throw new BadRequestException('Link X account failed!'); const existUser = await this.userRepo.findOne({ where: { xId } }); if (existUser) throw new BadRequestException('X account already linked!'); const ages = this.getAges(xId); const xInfo = await axios .get(`https://api.twitter.com/1.1/users/show.json?user_id=${xId}`, { headers: { Authorization: `Bearer ${this.xConfig.bearerToken}` }, }) .catch(() => null); return await this.userRepo.save({ uid: userData.uid, xId, x: { ages: ages > 0 ? ages : 1, id: xId, name: xInfo?.data?.name ?? '', username: xInfo?.data?.screen_name ?? '', avatar: xInfo?.data?.profile_image_url_https ?? '', }, }); } async authorize(userData?: User): Promise<{ customToken: string }> { const user = await this.findOrCreateUserByXInfo(userData); const customToken = await this.firebaseAuth.createCustomToken(user.uid, { xId: user.uid }); await this.validateQueue.add('validate-quest-by-type-job', { funkiId: user.uid, type: QuestType.LINK_SOCIAL, }); return { customToken, }; } }