73 lines
1.6 KiB
JavaScript
73 lines
1.6 KiB
JavaScript
import jwt from 'jsonwebtoken'
|
|
import Member from '../models/member.js'
|
|
import { connectDB } from './mongoose.js'
|
|
|
|
/**
|
|
* Verify JWT from cookie and return the decoded member.
|
|
* Throws 401 if token is missing or invalid.
|
|
*/
|
|
export async function requireAuth(event) {
|
|
await connectDB()
|
|
|
|
const token = getCookie(event, 'auth-token')
|
|
|
|
if (!token) {
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: 'Authentication required'
|
|
})
|
|
}
|
|
|
|
let decoded
|
|
try {
|
|
decoded = jwt.verify(token, useRuntimeConfig().jwtSecret)
|
|
} catch (err) {
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: 'Invalid or expired token'
|
|
})
|
|
}
|
|
|
|
const member = await Member.findById(decoded.memberId)
|
|
|
|
if (!member) {
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: 'Member not found'
|
|
})
|
|
}
|
|
|
|
if (member.status === 'suspended' || member.status === 'cancelled') {
|
|
throw createError({
|
|
statusCode: 403,
|
|
statusMessage: 'Account is ' + member.status
|
|
})
|
|
}
|
|
|
|
// Verify session has not been revoked (tokenVersion incremented on logout)
|
|
if (decoded.tv !== member.tokenVersion) {
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: 'Session has been revoked'
|
|
})
|
|
}
|
|
|
|
return member
|
|
}
|
|
|
|
/**
|
|
* Verify JWT and require admin role.
|
|
* Throws 401 if not authenticated, 403 if not admin.
|
|
*/
|
|
export async function requireAdmin(event) {
|
|
const member = await requireAuth(event)
|
|
|
|
if (member.role !== 'admin') {
|
|
throw createError({
|
|
statusCode: 403,
|
|
statusMessage: 'Admin access required'
|
|
})
|
|
}
|
|
|
|
return member
|
|
}
|