import { NextResponse } from 'next/server' import fs from 'fs' import path from 'path' // Use /tmp for temporary message storage // Messages will reset on rebuilds, which is fine for a global chat const dataFilePath = path.join('/tmp', 'messages.json') // Simple bad word list (expand as needed) const BAD_WORDS = [ // English 'badword', 'spam', 'toxic', 'hate', 'violence', 'kill', 'stupid', 'idiot', 'fuck', 'fuxk', 'fck', 'shit', 'sh!t', 'bitch', 'asshole', 'damn', 'hell', 'crap', 'piss', 'dick', 'cock', 'pussy', 'bastard', 'slut', 'whore', // Spanish 'puto', 'mierda', 'coño', 'cabron', 'pendejo', 'joder', // French 'merde', 'putain', 'connard', 'salope', 'encule', // German 'scheisse', 'arschloch', 'schlampe', 'fotze', // Italian 'cazzo', 'merda', 'vaffanculo', 'stronzo', // Portuguese 'porra', 'caralho', 'merda', 'puta', // Russian (transliterated) 'cyka', 'blyat', 'nahui', 'pizda', // Hindi (transliterated) 'madarchod', 'bhenchod', 'chutiya', 'kutta', 'kamina' ] interface Message { id: string text: string sender: string userId: string timestamp: number } const getMessages = (): Message[] => { try { if (!fs.existsSync(dataFilePath)) { fs.writeFileSync(dataFilePath, '[]', 'utf8') return [] } const fileData = fs.readFileSync(dataFilePath, 'utf8') return JSON.parse(fileData) } catch (error) { console.error('Error reading messages:', error) return [] } } const saveMessages = (messages: Message[]) => { try { fs.writeFileSync(dataFilePath, JSON.stringify(messages, null, 2), 'utf8') } catch (error) { console.error('Error saving messages:', error) } } export async function GET() { const messages = getMessages() return NextResponse.json(messages, { headers: { 'Content-Type': 'application/json; charset=utf-8' } }) } export async function POST(request: Request) { try { const body = await request.json() const { text, sender, userId } = body // 1. Validation: Length if (!text || text.length > 200) { return NextResponse.json({ error: 'Message too long (max 200 chars)' }, { status: 400 }) } if (!text.trim()) { return NextResponse.json({ error: 'Message cannot be empty' }, { status: 400 }) } // 2. Validation: Toxicity (whole word matching only) const lowerText = text.toLowerCase() const containsBadWord = BAD_WORDS.some(word => { // Use word boundaries to match whole words only const regex = new RegExp(`\\b${word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'i') return regex.test(text) }) if (containsBadWord) { return NextResponse.json({ error: 'Message contains inappropriate content' }, { status: 400 }) } const messages = getMessages() const now = Date.now() // 3. Validation: Spam (Rate Limiting) // Check if this user sent a message in the last 2 seconds const lastMessageFromUser = messages .filter(m => m.userId === userId) .sort((a, b) => b.timestamp - a.timestamp)[0] if (lastMessageFromUser && (now - lastMessageFromUser.timestamp) < 2000) { return NextResponse.json({ error: 'You are sending messages too fast. Please wait.' }, { status: 429 }) } // Check for duplicate message from same user if (lastMessageFromUser && lastMessageFromUser.text === text) { return NextResponse.json({ error: 'Do not send duplicate messages.' }, { status: 400 }) } const newMessage: Message = { id: Math.random().toString(36).substring(2, 15), text: text.trim(), sender: sender || 'Anonymous', userId: userId, timestamp: now } // Keep only last 100 messages to prevent file from growing too large const updatedMessages = [...messages, newMessage].slice(-100) saveMessages(updatedMessages) return NextResponse.json(updatedMessages, { headers: { 'Content-Type': 'application/json; charset=utf-8' } }) } catch (error) { console.error('Error processing message:', error) return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }) } }