Add Zod validation, fix mass assignment, remove test endpoints and dead code
- Add centralized Zod schemas (server/utils/schemas.js) and validateBody utility for all API endpoints - Fix critical mass assignment in member creation: raw body no longer passed to new Member(), only validated fields (email, name, circle, contributionTier) are accepted - Apply Zod validation to login, profile patch, event registration, updates, verify-payment, and admin event creation endpoints - Fix logout cookie flags to match login (httpOnly: true, secure conditional on NODE_ENV) - Delete unauthenticated test/debug endpoints (test-connection, test-subscription, test-bot) - Remove sensitive console.log statements from Helcim and member endpoints - Remove unused bcryptjs dependency - Add 10MB file size limit on image uploads - Use runtime config for JWT secret across all endpoints - Add 38 validation tests (117 total, all passing)
This commit is contained in:
parent
26c300c357
commit
b7279f57d1
41 changed files with 467 additions and 321 deletions
|
|
@ -3,6 +3,8 @@ import jwt from "jsonwebtoken";
|
|||
import { Resend } from "resend";
|
||||
import Member from "../../models/member.js";
|
||||
import { connectDB } from "../../utils/mongoose.js";
|
||||
import { validateBody } from "../../utils/validateBody.js";
|
||||
import { emailSchema } from "../../utils/schemas.js";
|
||||
|
||||
const resend = new Resend(process.env.RESEND_API_KEY);
|
||||
|
||||
|
|
@ -10,14 +12,7 @@ export default defineEventHandler(async (event) => {
|
|||
// Connect to database
|
||||
await connectDB();
|
||||
|
||||
const { email } = await readBody(event);
|
||||
|
||||
if (!email) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Email is required",
|
||||
});
|
||||
}
|
||||
const { email } = await validateBody(event, emailSchema);
|
||||
|
||||
const GENERIC_MESSAGE = "If this email is registered, we've sent a login link.";
|
||||
|
||||
|
|
@ -31,10 +26,11 @@ export default defineEventHandler(async (event) => {
|
|||
};
|
||||
}
|
||||
|
||||
// Generate magic link token
|
||||
// Generate magic link token (use runtime config for consistency with verify/requireAuth)
|
||||
const config = useRuntimeConfig(event);
|
||||
const token = jwt.sign(
|
||||
{ memberId: member._id },
|
||||
process.env.JWT_SECRET,
|
||||
config.jwtSecret,
|
||||
{ expiresIn: "15m" },
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
export default defineEventHandler(async (event) => {
|
||||
// Clear the auth token cookie
|
||||
// Clear the auth token cookie (flags must match login for proper clearing)
|
||||
setCookie(event, 'auth-token', '', {
|
||||
httpOnly: false, // Match the original cookie settings
|
||||
secure: false, // Don't require HTTPS in development
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax',
|
||||
maxAge: 0 // Expire immediately
|
||||
})
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export default defineEventHandler(async (event) => {
|
|||
}
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET)
|
||||
const decoded = jwt.verify(token, useRuntimeConfig().jwtSecret)
|
||||
const member = await Member.findById(decoded.memberId).select('-__v')
|
||||
|
||||
if (!member) {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,9 @@ export default defineEventHandler(async (event) => {
|
|||
}
|
||||
|
||||
try {
|
||||
// Verify the JWT token
|
||||
const decoded = jwt.verify(token, process.env.JWT_SECRET)
|
||||
// Verify the JWT token (use runtime config for consistency with login/requireAuth)
|
||||
const config = useRuntimeConfig(event)
|
||||
const decoded = jwt.verify(token, config.jwtSecret)
|
||||
const member = await Member.findById(decoded.memberId)
|
||||
|
||||
if (!member) {
|
||||
|
|
@ -32,7 +33,7 @@ export default defineEventHandler(async (event) => {
|
|||
// Create a new session token for the authenticated user
|
||||
const sessionToken = jwt.sign(
|
||||
{ memberId: member._id, email: member.email },
|
||||
process.env.JWT_SECRET,
|
||||
config.jwtSecret,
|
||||
{ expiresIn: '7d' }
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue