108 lines
2.9 KiB
TypeScript
108 lines
2.9 KiB
TypeScript
import { generateToken } from '~/server/utils/auth'
|
|
import { prisma } from '~/server/utils/prisma'
|
|
|
|
interface FirebaseUser {
|
|
localId: string
|
|
email: string
|
|
displayName?: string
|
|
photoUrl?: string
|
|
}
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const body = await readBody(event)
|
|
const { idToken } = body
|
|
|
|
if (!idToken) {
|
|
throw createError({ statusCode: 400, message: 'Firebase ID token required' })
|
|
}
|
|
|
|
const config = useRuntimeConfig()
|
|
const apiKey = config.firebaseApiKey || config.public.firebaseApiKey
|
|
|
|
if (!apiKey) {
|
|
throw createError({ statusCode: 500, message: 'Firebase API key not configured' })
|
|
}
|
|
|
|
console.log('[Auth] Received idToken, length:', idToken?.length || 0)
|
|
console.log('[Auth] Using API key (masked):', apiKey ? `${apiKey.slice(0, 6)}...${apiKey.slice(-4)}` : 'EMPTY')
|
|
|
|
let verifyRes: any
|
|
try {
|
|
verifyRes = await $fetch<any>(
|
|
`https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=${apiKey}`,
|
|
{ method: 'POST', body: { idToken } }
|
|
)
|
|
} catch (err: any) {
|
|
console.error('[Auth] Firebase token verification failed:', err?.data || err?.message || err)
|
|
throw createError({ statusCode: 401, message: 'Invalid Firebase token' })
|
|
}
|
|
|
|
if (!verifyRes?.users?.[0]) {
|
|
throw createError({ statusCode: 401, message: 'Invalid Firebase token' })
|
|
}
|
|
|
|
const fbUser: FirebaseUser = verifyRes.users[0]
|
|
const email = fbUser.email
|
|
// Очищаем username: заменяем пробелы на дефисы и убираем спецсимволы
|
|
const username = email.split('@')[0].toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-_]/g, '')
|
|
const userId = fbUser.localId
|
|
|
|
let user: any
|
|
try {
|
|
user = await prisma.user.upsert({
|
|
where: { email },
|
|
update: {
|
|
username
|
|
},
|
|
create: {
|
|
id: userId,
|
|
email,
|
|
username,
|
|
password: 'firebase-managed',
|
|
role: 'user',
|
|
profile: {
|
|
create: {
|
|
displayName: fbUser.displayName || username,
|
|
avatar: fbUser.photoUrl || `https://api.dicebear.com/7.x/avataaars/svg?seed=${userId}`
|
|
}
|
|
}
|
|
},
|
|
include: {
|
|
profile: true
|
|
}
|
|
})
|
|
} catch (dbErr: any) {
|
|
console.warn('[Auth] Database offline, creating local dev session for:', email, dbErr.message)
|
|
user = {
|
|
id: userId,
|
|
email,
|
|
username,
|
|
role: 'user',
|
|
profile: {
|
|
displayName: fbUser.displayName || username,
|
|
avatar: fbUser.photoUrl || `https://api.dicebear.com/7.x/avataaars/svg?seed=${userId}`
|
|
}
|
|
}
|
|
}
|
|
|
|
const token = generateToken({
|
|
id: user.id,
|
|
email: user.email,
|
|
username: user.username,
|
|
displayName: user.profile?.displayName || user.username,
|
|
role: user.role
|
|
})
|
|
|
|
return {
|
|
message: 'Google sign-in successful',
|
|
token,
|
|
user: {
|
|
id: user.id,
|
|
email: user.email,
|
|
username: user.username,
|
|
role: user.role,
|
|
photoUrl: fbUser.photoUrl
|
|
}
|
|
}
|
|
})
|