feat: add password change and reset via email code
This commit is contained in:
@@ -138,6 +138,39 @@ export async function registerAuthRoutes(fastify) {
|
||||
return { token, user: mapUserForClient(user) }
|
||||
})
|
||||
|
||||
fastify.post('/api/auth/forgot-password', async (request) => {
|
||||
const email = normalizeEmail(request.body?.email)
|
||||
if (!email || !email.includes('@')) return { ok: true }
|
||||
|
||||
if (isAdminEmail(email)) return { ok: true }
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { email } })
|
||||
if (!user || !user.passwordHash) return { ok: true }
|
||||
|
||||
await issueEmailCode({ email, purpose: 'reset_password' })
|
||||
return { ok: true }
|
||||
})
|
||||
|
||||
fastify.post('/api/auth/reset-password', async (request, reply) => {
|
||||
const email = normalizeEmail(request.body?.email)
|
||||
const code = String(request.body?.code || '').trim()
|
||||
const newPassword = String(request.body?.newPassword || '')
|
||||
|
||||
if (!email || !email.includes('@')) return reply.code(400).send({ error: 'Некорректная почта' })
|
||||
if (!code || code.length !== 6) return reply.code(400).send({ error: 'Код должен быть из 6 цифр' })
|
||||
|
||||
const ok = await verifyEmailCode({ email, purpose: 'reset_password', code })
|
||||
if (!ok) return reply.code(401).send({ error: 'Неверный или истёкший код' })
|
||||
|
||||
const passwordErr = validatePassword(newPassword)
|
||||
if (passwordErr) return reply.code(400).send({ error: passwordErr })
|
||||
|
||||
const passwordHash = await hashPassword(newPassword)
|
||||
await prisma.user.update({ where: { email }, data: { passwordHash } })
|
||||
|
||||
return { ok: true }
|
||||
})
|
||||
|
||||
fastify.get('/api/me', { preHandler: [fastify.authenticate] }, async (request) => {
|
||||
const userId = request.user.sub
|
||||
const user = await prisma.user.findUnique({ where: { id: userId } })
|
||||
@@ -183,6 +216,30 @@ export async function registerAuthRoutes(fastify) {
|
||||
return { ok: true }
|
||||
})
|
||||
|
||||
fastify.post('/api/me/change-password', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||
const userId = request.user.sub
|
||||
if (isAdminEmail(request.user.email)) {
|
||||
return reply.code(403).send({ error: 'Администратор не может менять пароль' })
|
||||
}
|
||||
|
||||
const user = await prisma.user.findUnique({ where: { id: userId } })
|
||||
if (!user) return reply.code(404).send({ error: 'Пользователь не найден' })
|
||||
if (!user.passwordHash) return reply.code(400).send({ error: 'Пароль не установлен. Используйте установку пароля.' })
|
||||
|
||||
const oldPassword = String(request.body?.oldPassword || '')
|
||||
const valid = await comparePassword(oldPassword, user.passwordHash)
|
||||
if (!valid) return reply.code(401).send({ error: 'Неверный текущий пароль' })
|
||||
|
||||
const newPassword = String(request.body?.newPassword || '')
|
||||
const passwordErr = validatePassword(newPassword)
|
||||
if (passwordErr) return reply.code(400).send({ error: passwordErr })
|
||||
|
||||
const passwordHash = await hashPassword(newPassword)
|
||||
await prisma.user.update({ where: { id: userId }, data: { passwordHash } })
|
||||
|
||||
return { ok: true }
|
||||
})
|
||||
|
||||
fastify.delete('/api/me/oauth/:provider', { preHandler: [fastify.authenticate] }, async (request, reply) => {
|
||||
const userId = request.user.sub
|
||||
const provider = request.params?.provider
|
||||
|
||||
Reference in New Issue
Block a user