헤더 검색 중앙 정렬·Resend 이메일 OTP·비밀번호 찾기 (v0.0.99)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
65
server/api/auth/password-reset/confirm.post.js
Normal file
65
server/api/auth/password-reset/confirm.post.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import bcrypt from 'bcrypt'
|
||||
import { z } from 'zod'
|
||||
import { createError, readBody } from 'h3'
|
||||
import { updateMemberPasswordByEmail } from '../../../repositories/member-repository'
|
||||
import { verifyAndConsumeEmailOtp } from '../../../repositories/email-otp-repository'
|
||||
|
||||
const bodySchema = z.object({
|
||||
email: z.string().trim().email(),
|
||||
code: z.string().regex(/^\d{6}$/),
|
||||
newPassword: z.string().min(8).max(32)
|
||||
})
|
||||
|
||||
/**
|
||||
* 이메일 OTP로 비밀번호를 재설정한다.
|
||||
* @param {import('h3').H3Event} event - 요청 이벤트
|
||||
* @returns {Promise<{ ok: boolean }>}
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
const parsed = bodySchema.safeParse(await readBody(event))
|
||||
if (!parsed.success) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '요청 형식이 올바르지 않습니다.'
|
||||
})
|
||||
}
|
||||
|
||||
const config = useRuntimeConfig()
|
||||
const pepper = String(config.emailOtpPepper || config.memberSessionSecret || '').trim()
|
||||
if (!pepper) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
message: '서버 인증 설정이 올바르지 않습니다.'
|
||||
})
|
||||
}
|
||||
|
||||
const email = parsed.data.email.trim().toLowerCase()
|
||||
const verify = await verifyAndConsumeEmailOtp({
|
||||
email,
|
||||
purpose: 'password_reset',
|
||||
code: parsed.data.code,
|
||||
pepper
|
||||
})
|
||||
|
||||
if (!verify.ok) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '인증번호가 올바르지 않거나 만료되었습니다.'
|
||||
})
|
||||
}
|
||||
|
||||
const nextHash = await bcrypt.hash(parsed.data.newPassword, 12)
|
||||
const updated = await updateMemberPasswordByEmail({
|
||||
email,
|
||||
passwordHash: nextHash
|
||||
})
|
||||
|
||||
if (!updated) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '계정을 찾을 수 없습니다. 다시 인증번호를 요청해 주세요.'
|
||||
})
|
||||
}
|
||||
|
||||
return { ok: true }
|
||||
})
|
||||
Reference in New Issue
Block a user