feat(chat): implement spam protection and profanity filter
Add comprehensive message validation with three protection mechanisms: 1. Rate Limiting: 10 messages per minute per user 2. Duplicate Detection: Prevents sending identical messages within 1 minute 3. Profanity Filter: Blocks inappropriate language (English + Polish) Implementation: - New messageValidation.js middleware with validateMessage() function - Integrated into both event chat and match chat handlers - Uses bad-words library (v2.0.0 for CommonJS compatibility) - In-memory tracking with automatic cleanup every 5 minutes - User-friendly error messages for each validation type Technical details: - Rate limit: 10 msg/min sliding window - Duplicate check: Last 5 messages within 60s window - Profanity: bad-words + 11 Polish words - Memory management: Periodic cleanup of expired data
This commit is contained in:
@@ -3,6 +3,7 @@ const { verifyToken } = require('../utils/auth');
|
||||
const { prisma } = require('../utils/db');
|
||||
const { ACTIONS, log: activityLog } = require('../services/activityLog');
|
||||
const { MESSAGE_MAX_LENGTH } = require('../constants');
|
||||
const { validateMessage } = require('../middleware/messageValidation');
|
||||
|
||||
// Track active users in each event room
|
||||
const activeUsers = new Map(); // eventId -> Set of { socketId, userId, username, avatar }
|
||||
@@ -311,17 +312,10 @@ function initializeSocket(httpServer) {
|
||||
return socket.emit('error', { message: 'Not in an event room' });
|
||||
}
|
||||
|
||||
// Validate message content
|
||||
if (!content || typeof content !== 'string') {
|
||||
return socket.emit('error', { message: 'Invalid message content' });
|
||||
}
|
||||
|
||||
if (content.trim().length === 0) {
|
||||
return socket.emit('error', { message: 'Message cannot be empty' });
|
||||
}
|
||||
|
||||
if (content.length > MESSAGE_MAX_LENGTH) {
|
||||
return socket.emit('error', { message: `Message too long. Maximum ${MESSAGE_MAX_LENGTH} characters allowed.` });
|
||||
// Validate message (length, rate limit, duplicates, profanity)
|
||||
const validation = validateMessage(socket.user.id, content);
|
||||
if (!validation.valid) {
|
||||
return socket.emit('error', { message: validation.error });
|
||||
}
|
||||
|
||||
const eventId = socket.currentEventId;
|
||||
@@ -448,17 +442,10 @@ function initializeSocket(httpServer) {
|
||||
// Send message to match room
|
||||
socket.on('send_match_message', async ({ matchId, content }) => {
|
||||
try {
|
||||
// Validate message content
|
||||
if (!content || typeof content !== 'string') {
|
||||
return socket.emit('error', { message: 'Invalid message content' });
|
||||
}
|
||||
|
||||
if (content.trim().length === 0) {
|
||||
return socket.emit('error', { message: 'Message cannot be empty' });
|
||||
}
|
||||
|
||||
if (content.length > MESSAGE_MAX_LENGTH) {
|
||||
return socket.emit('error', { message: `Message too long. Maximum ${MESSAGE_MAX_LENGTH} characters allowed.` });
|
||||
// Validate message (length, rate limit, duplicates, profanity)
|
||||
const validation = validateMessage(socket.user.id, content);
|
||||
if (!validation.valid) {
|
||||
return socket.emit('error', { message: validation.error });
|
||||
}
|
||||
|
||||
const roomName = `match_${matchId}`;
|
||||
|
||||
Reference in New Issue
Block a user