ghostguild-org/server/api/invite/verify.post.js
Jennie Robinson Faber 1c3273cee2
Some checks failed
Test / vitest (push) Successful in 14m0s
Test / playwright (push) Failing after 20m2s
Test / Notify on failure (push) Successful in 3s
Various pre-launch fixes.
2026-05-22 18:53:07 +01:00

43 lines
1.5 KiB
JavaScript

import jwt from 'jsonwebtoken'
import PreRegistration from '../../models/preRegistration.js'
import { connectDB } from '../../utils/mongoose.js'
export default defineEventHandler(async (event) => {
const { token } = await validateBody(event, inviteVerifySchema)
const config = useRuntimeConfig(event)
await connectDB()
let decoded
try {
decoded = jwt.verify(token, config.jwtSecret)
} catch {
throw createError({ statusCode: 401, statusMessage: 'Invalid or expired invitation link' })
}
if (decoded.type !== 'prereg-invite') {
throw createError({ statusCode: 401, statusMessage: 'Invalid or expired invitation link' })
}
const preReg = await PreRegistration.findById(decoded.preRegistrationId)
if (!preReg) {
throw createError({ statusCode: 401, statusMessage: 'Invalid or expired invitation link' })
}
if (preReg.status === 'accepted') {
throw createError({ statusCode: 400, statusMessage: 'This invitation has already been accepted' })
}
// Match the jti so that re-invite (which rotates the jti) kills old links.
// The burn happens in accept.post.js once a Member is created — keeps verify
// idempotent so the form survives a refresh.
if (!decoded.jti || decoded.jti !== preReg.magicLinkJti) {
throw createError({ statusCode: 401, statusMessage: 'Invalid or expired invitation link' })
}
return {
preRegistrationId: preReg._id,
name: preReg.name,
email: preReg.email,
city: preReg.city,
}
})