feat: adiciona fluxo de redefinição de senha e melhora página de configurações
- Adiciona página /recuperar para solicitar redefinição de senha - Adiciona página /redefinir-senha para definir nova senha com token - Cria APIs /api/auth/forgot-password e /api/auth/reset-password - Adiciona notificação por e-mail quando ticket é criado - Repagina página de configurações removendo informações técnicas - Adiciona script de teste para todos os tipos de e-mail - Corrige acentuações em templates de e-mail 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
300179279a
commit
1bc08d3a5f
10 changed files with 1258 additions and 166 deletions
97
src/app/api/auth/reset-password/route.ts
Normal file
97
src/app/api/auth/reset-password/route.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { NextResponse } from "next/server"
|
||||
import { hashPassword } from "better-auth/crypto"
|
||||
|
||||
import { prisma } from "@/lib/prisma"
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { token, password } = body
|
||||
|
||||
if (!token || typeof token !== "string") {
|
||||
return NextResponse.json({ error: "Token inválido" }, { status: 400 })
|
||||
}
|
||||
|
||||
if (!password || typeof password !== "string" || password.length < 6) {
|
||||
return NextResponse.json({ error: "A senha deve ter pelo menos 6 caracteres" }, { status: 400 })
|
||||
}
|
||||
|
||||
// Busca o token de verificação
|
||||
const verification = await prisma.authVerification.findFirst({
|
||||
where: {
|
||||
value: token,
|
||||
identifier: { startsWith: "password-reset:" },
|
||||
expiresAt: { gt: new Date() },
|
||||
},
|
||||
})
|
||||
|
||||
if (!verification) {
|
||||
return NextResponse.json({ error: "Token inválido ou expirado" }, { status: 400 })
|
||||
}
|
||||
|
||||
// Extrai o userId do identifier
|
||||
const userId = verification.identifier.replace("password-reset:", "")
|
||||
|
||||
// Busca o usuário
|
||||
const user = await prisma.authUser.findUnique({
|
||||
where: { id: userId },
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
return NextResponse.json({ error: "Usuário não encontrado" }, { status: 400 })
|
||||
}
|
||||
|
||||
// Hash da nova senha
|
||||
const hashedPassword = await hashPassword(password)
|
||||
|
||||
// Atualiza a conta do usuário com a nova senha
|
||||
await prisma.authAccount.updateMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
providerId: "credential",
|
||||
},
|
||||
data: {
|
||||
password: hashedPassword,
|
||||
},
|
||||
})
|
||||
|
||||
// Remove o token usado
|
||||
await prisma.authVerification.delete({
|
||||
where: { id: verification.id },
|
||||
})
|
||||
|
||||
return NextResponse.json({ success: true })
|
||||
} catch (error) {
|
||||
console.error("[RESET_PASSWORD] Erro:", error)
|
||||
return NextResponse.json({ error: "Erro ao redefinir senha" }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
// GET para validar se o token é válido (usado pela página)
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url)
|
||||
const token = searchParams.get("token")
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.json({ valid: false, error: "Token não fornecido" })
|
||||
}
|
||||
|
||||
const verification = await prisma.authVerification.findFirst({
|
||||
where: {
|
||||
value: token,
|
||||
identifier: { startsWith: "password-reset:" },
|
||||
expiresAt: { gt: new Date() },
|
||||
},
|
||||
})
|
||||
|
||||
if (!verification) {
|
||||
return NextResponse.json({ valid: false, error: "Token inválido ou expirado" })
|
||||
}
|
||||
|
||||
return NextResponse.json({ valid: true })
|
||||
} catch (error) {
|
||||
console.error("[RESET_PASSWORD] Erro ao validar token:", error)
|
||||
return NextResponse.json({ valid: false, error: "Erro ao validar token" })
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue