From e1ba65327635f500496f4480b670ce6aa478cf33 Mon Sep 17 00:00:00 2001 From: TheMaddax Date: Sat, 4 Oct 2025 09:11:45 -0600 Subject: [PATCH] fix: disable Redis and fix email configuration - Remove Redis rate limiting for security reasons - Update SMTP port from 587 to 2525 (matching working websites) - Add requireTLS to nodemailer configuration - Remove Redis environment variables - Update rate-limit.ts with graceful fallback - Add debugging logs to contact API - Contact form functionality verified and working --- .env.local | 7 ++-- cline_docs/activeContext.md | 34 +++++++++--------- src/app/api/contact/route.ts | 24 ++++++++----- src/lib/rate-limit.ts | 67 ++++++------------------------------ 4 files changed, 45 insertions(+), 87 deletions(-) diff --git a/.env.local b/.env.local index 044a5e2..92cae66 100644 --- a/.env.local +++ b/.env.local @@ -1,9 +1,6 @@ GOOGLE_EMAIL=system@sigd.net SMTP_HOST=smtp.gmail.com -SMTP_PORT=587 +SMTP_PORT=2525 SMTP_SECURE=false RECIPIENT_EMAIL=chris@sigd.net -GOOGLE_APP_PASSWORD=fvjivgqewtmtpdez -UPSTASH_REDIS_REST_URL=https://gusc1-resolved-jaybird-30779.upstash.io -UPSTASH_REDIS_REST_TOKEN=AXg7ASQgNDMzMDE0MTYtNWE0Ni00OTc3LThhYjktM2IxMzMxNGMyMzMxNWRiNGMyOGU2MjE0NGUyNTkwMTQyNmUxZTU2NzE4NDI= - +GOOGLE_APP_PASSWORD=fvjivgqewtmtpdez diff --git a/cline_docs/activeContext.md b/cline_docs/activeContext.md index 2140244..78833ee 100644 --- a/cline_docs/activeContext.md +++ b/cline_docs/activeContext.md @@ -7,27 +7,27 @@ - Ready for development tasks ## What I'm Working On Now -- Just completed Memory Bank setup -- No active development tasks currently -- Awaiting user instructions for next steps +- Recently completed Redis removal and email configuration fixes +- Contact form functionality has been verified and is working +- Ready to commit changes to git repository ## Recent Changes -- Created `cline_docs/` directory -- Established complete Memory Bank documentation: - - productContext.md - Project purpose and goals - - activeContext.md - Current work status (this file) - - systemPatterns.md - Architecture and patterns - - techContext.md - Technical setup and dependencies - - progress.md - Development status +- **Disabled Redis for security reasons:** + - Removed Redis rate limiting from contact API route + - Removed Redis environment variables from .env.local + - Updated rate-limit.ts to provide graceful fallback without Redis +- **Fixed email configuration:** + - Updated SMTP port from 587 to 2525 (matching working websites) + - Added requireTLS: true to nodemailer configuration + - Added debugging logs to contact API for troubleshooting +- **Contact form verification:** + - User confirmed contact form is now working properly + - Email sending functionality restored ## Next Steps -- Await user instructions for specific tasks -- Potential areas for development: - - Feature enhancements - - Bug fixes - - Content updates - - Performance optimizations - - Accessibility improvements +- Commit current changes to git with proper message +- Clean up any debugging logs if needed +- Continue with any additional development tasks ## Current Understanding The website is a professional portfolio for Chris Haulmark, a global Deaf advocate. It's built with Next.js 14, TypeScript, and TailwindCSS. The site includes: diff --git a/src/app/api/contact/route.ts b/src/app/api/contact/route.ts index bba9ff7..5127533 100644 --- a/src/app/api/contact/route.ts +++ b/src/app/api/contact/route.ts @@ -1,6 +1,5 @@ import { NextResponse } from 'next/server' import nodemailer from 'nodemailer' -import { rateLimit } from '@/lib/rate-limit' interface FormData { name: string @@ -43,16 +42,11 @@ const sanitizeInput = (input: string): string => { export async function POST(req: Request) { try { - // Rate limiting check - const rateLimitResult = await rateLimit() - if (!rateLimitResult.success) { - return NextResponse.json( - { success: false, message: 'Too many requests. Please try again later.' }, - { status: 429 } - ) - } + // Rate limiting disabled for security reasons + console.log('Contact API called') const data: FormData = await req.json() + console.log('Form data received:', { ...data, message: data.message?.substring(0, 50) + '...' }) // Input validation const validation = validateInput(data) @@ -71,10 +65,20 @@ export async function POST(req: Request) { message: sanitizeInput(data.message) } + console.log('Environment check:', { + host: process.env.SMTP_HOST, + port: process.env.SMTP_PORT, + secure: process.env.SMTP_SECURE, + hasEmail: !!process.env.GOOGLE_EMAIL, + hasPassword: !!process.env.GOOGLE_APP_PASSWORD, + hasRecipient: !!process.env.RECIPIENT_EMAIL + }) + const transporter = nodemailer.createTransport({ host: process.env.SMTP_HOST, port: Number(process.env.SMTP_PORT), secure: process.env.SMTP_SECURE === 'true', + requireTLS: true, auth: { user: process.env.GOOGLE_EMAIL, pass: process.env.GOOGLE_APP_PASSWORD, @@ -99,7 +103,9 @@ export async function POST(req: Request) { `, } + console.log('Attempting to send email...') await transporter.sendMail(mailOptions) + console.log('Email sent successfully') return NextResponse.json({ success: true, diff --git a/src/lib/rate-limit.ts b/src/lib/rate-limit.ts index cb68ad4..5c132eb 100644 --- a/src/lib/rate-limit.ts +++ b/src/lib/rate-limit.ts @@ -1,5 +1,5 @@ -import { Redis } from '@upstash/redis' -import { headers } from 'next/headers' +// Redis disabled for security reasons +// Graceful fallback without rate limiting export interface RateLimitConfig { interval: number // in seconds @@ -13,60 +13,15 @@ export interface RateLimitResult { reset: number // timestamp in seconds } -export class RateLimit { - private redis: Redis - private prefix: string - - constructor() { - this.redis = Redis.fromEnv() - this.prefix = 'ratelimit' - } - - private getIP(): string { - const headersList = headers() - const forwardedFor = headersList.get('x-forwarded-for') - const realIP = headersList.get('x-real-ip') - const ip = forwardedFor?.split(',')[0] || realIP || 'unknown' - return ip - } - - private getKey(identifier: string): string { - return `${this.prefix}:${identifier}` - } - - async check(config: RateLimitConfig): Promise { - const ip = this.getIP() - const key = this.getKey(ip) - const now = Math.floor(Date.now() / 1000) - const windowStart = now - (now % config.interval) - const windowKey = `${key}:${windowStart}` - - const pipeline = this.redis.pipeline() - pipeline.incr(windowKey) - pipeline.expire(windowKey, config.interval) - - const [count] = await pipeline.exec() - const remaining = Math.max(0, config.limit - (count as number)) - - return { - success: (count as number) <= config.limit, - limit: config.limit, - remaining, - reset: windowStart + config.interval - } - } -} - -// Default configuration -const DEFAULT_CONFIG: RateLimitConfig = { - interval: 60 * 60, // 1 hour - limit: 5 // 5 requests per hour -} - -// Helper function for easy usage +// Helper function for easy usage - always allows requests export async function rateLimit( - config: RateLimitConfig = DEFAULT_CONFIG + config?: RateLimitConfig ): Promise { - const limiter = new RateLimit() - return limiter.check(config) + // Always return success since Redis is disabled + return { + success: true, + limit: 999, + remaining: 999, + reset: Math.floor(Date.now() / 1000) + 3600 // 1 hour from now + } }