82 lines
3.0 KiB
JavaScript
82 lines
3.0 KiB
JavaScript
import crypto from 'node:crypto'
|
|
import { normalizeEmail } from '../lib/auth.js'
|
|
import { prisma } from '../lib/prisma.js'
|
|
import { mapUserForClient } from './auth.js'
|
|
|
|
export async function registerAuthSessionRoutes(fastify) {
|
|
fastify.get('/api/me', { preHandler: [fastify.authenticate] }, async (request) => {
|
|
const userId = request.user.sub
|
|
const user = await prisma.user.findUnique({ where: { id: userId } })
|
|
if (!user) return { user: null }
|
|
return { user: mapUserForClient(user) }
|
|
})
|
|
|
|
fastify.get('/api/me/auth-methods', { preHandler: [fastify.authenticate] }, async (request) => {
|
|
const userId = request.user.sub
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: userId },
|
|
include: { oauthAccounts: { select: { provider: true } } },
|
|
})
|
|
if (!user) return { methods: [] }
|
|
|
|
const providers = user.oauthAccounts.map((a) => a.provider)
|
|
return {
|
|
methods: [
|
|
{ type: 'password', active: Boolean(user.passwordHash) },
|
|
{ type: 'vk', active: providers.includes('vk') },
|
|
{ type: 'yandex', active: providers.includes('yandex') },
|
|
],
|
|
}
|
|
})
|
|
|
|
fastify.patch('/api/me/email', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
|
const userId = request.user.sub
|
|
const rawEmail = typeof request.body?.email === 'string' ? request.body.email.trim() : ''
|
|
|
|
if (!rawEmail || !rawEmail.includes('@')) {
|
|
return reply.code(400).send({ error: 'Некорректная почта' })
|
|
}
|
|
|
|
const email = normalizeEmail(rawEmail)
|
|
|
|
const existing = await prisma.user.findUnique({ where: { email } })
|
|
if (existing && existing.id !== userId) {
|
|
return reply.code(409).send({ error: 'Эта почта уже используется' })
|
|
}
|
|
|
|
await prisma.pendingEmail.deleteMany({ where: { userId } })
|
|
|
|
const token = crypto.randomUUID()
|
|
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000)
|
|
|
|
await prisma.pendingEmail.create({
|
|
data: { userId, email, token, expiresAt },
|
|
})
|
|
|
|
return { verificationUrl: `/api/me/verify-email?token=${token}` }
|
|
})
|
|
|
|
fastify.get('/api/me/verify-email', async (request, reply) => {
|
|
const token = typeof request.query?.token === 'string' ? request.query.token : ''
|
|
|
|
if (!token) {
|
|
return reply.code(400).send({ error: 'Отсутствует токен подтверждения' })
|
|
}
|
|
|
|
const pending = await prisma.pendingEmail.findUnique({ where: { token } })
|
|
if (!pending || pending.expiresAt < new Date()) {
|
|
return reply.code(400).send({ error: 'Токен подтверждения недействителен или истёк' })
|
|
}
|
|
|
|
await prisma.user.update({
|
|
where: { id: pending.userId },
|
|
data: { email: pending.email },
|
|
})
|
|
|
|
await prisma.pendingEmail.delete({ where: { id: pending.id } })
|
|
|
|
const clientUrl = (process.env.CLIENT_PUBLIC_URL || 'http://127.0.0.1:5173').replace(/\/$/, '')
|
|
return reply.redirect(`${clientUrl}/me?emailVerified=1`)
|
|
})
|
|
}
|