1773ed5f95
Mirror to GitHub / mirror (push) Successful in 26s
Test and Lint / backend-test (push) Successful in 1m11s
continuous-integration/drone/push Build is passing
Test and Lint / frontend-test (push) Successful in 2m28s
Version and Release / version-bump (push) Successful in 32s
Version and Release / trigger-drone (push) Has been skipped
Original: feat: enhance security logging and ensure rate limit blocks are properly tracked - Add comprehensive logging for rate limit blocks with full request details - IP address (with proper proxy detection), user agent, headers, timestamps - Rate limit info (current count, limit, remaining, reset time) - Separate tracking for auth vs general endpoints - Enhance authentication failure logging - JWT validation failures with detailed error info - Admin auth attempts without token - Failed token validation with user context - All events include IP, path, method, user agent - Improve Winston logger configuration for production - Add automatic log rotation (10MB errors, 50MB combined) - Create separate security.log for auth/rate limit events - Ensure logs directory exists automatically - Add structured JSON format for log aggregation - Support container logging with LOG_TO_CONSOLE env var - Create comprehensive documentation - Security logging guide with examples - Monitoring recommendations - Configuration reference - Add test script to verify logging functionality All rate limit settings remain configurable via admin panel: - Window duration, max requests, auth limits - Skip authenticated requests option - Public endpoints only option 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
102 lines
3.2 KiB
JavaScript
102 lines
3.2 KiB
JavaScript
const cron = require('node-cron');
|
|
const { db } = require('../database/db');
|
|
const { archiveEvent } = require('./archiveService');
|
|
const { queueEmail } = require('./emailProcessor');
|
|
const logger = require('../utils/logger');
|
|
const { formatDate } = require('../utils/dateFormatter');
|
|
const { formatBoolean } = require('../utils/dbCompat');
|
|
|
|
function startExpirationChecker() {
|
|
// Check every hour for expired events and warnings
|
|
cron.schedule('0 * * * *', async () => {
|
|
await checkExpirations();
|
|
});
|
|
|
|
logger.info('Expiration checker started');
|
|
}
|
|
|
|
async function checkExpirations() {
|
|
try {
|
|
const now = new Date();
|
|
const warningDate = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); // 7 days from now
|
|
|
|
// Check for events needing warning emails
|
|
const eventsNeedingWarning = await db('events')
|
|
.where('is_active', formatBoolean(true))
|
|
.where('is_archived', formatBoolean(false))
|
|
.where('expires_at', '<=', warningDate)
|
|
.where('expires_at', '>', now);
|
|
|
|
for (const event of eventsNeedingWarning) {
|
|
// Check if warning email already sent
|
|
const existingWarning = await db('email_queue')
|
|
.where('event_id', event.id)
|
|
.where('email_type', 'expiration_warning')
|
|
.first();
|
|
|
|
if (!existingWarning) {
|
|
await queueExpirationWarning(event);
|
|
}
|
|
}
|
|
|
|
// Check for expired events
|
|
const expiredEvents = await db('events')
|
|
.where('is_active', formatBoolean(true))
|
|
.where('is_archived', formatBoolean(false))
|
|
.where('expires_at', '<=', now);
|
|
|
|
for (const event of expiredEvents) {
|
|
await handleExpiredEvent(event);
|
|
}
|
|
|
|
} catch (error) {
|
|
logger.error('Error checking expirations:', error);
|
|
}
|
|
}
|
|
|
|
async function queueExpirationWarning(event) {
|
|
const daysRemaining = Math.ceil((new Date(event.expires_at) - new Date()) / (1000 * 60 * 60 * 24));
|
|
|
|
// Determine language based on email domain
|
|
const emailLang = event.host_email.endsWith('.de') ? 'de' : 'en';
|
|
|
|
// Queue email to host
|
|
await queueEmail(event.id, event.host_email, 'expiration_warning', {
|
|
host_name: event.host_name || event.host_email.split('@')[0],
|
|
event_name: event.event_name,
|
|
days_remaining: daysRemaining.toString(),
|
|
expiration_date: await formatDate(event.expires_at, emailLang),
|
|
gallery_link: event.share_link
|
|
});
|
|
|
|
logger.info(`Queued expiration warning for event ${event.slug}`);
|
|
}
|
|
|
|
async function handleExpiredEvent(event) {
|
|
try {
|
|
// Mark as inactive
|
|
await db('events').where('id', event.id).update({ is_active: formatBoolean(false) });
|
|
|
|
// Queue expiration emails
|
|
await queueEmail(event.id, event.host_email, 'gallery_expired', {
|
|
event_name: event.event_name,
|
|
admin_email: event.admin_email
|
|
});
|
|
|
|
// Also notify admin
|
|
await queueEmail(event.id, event.admin_email, 'gallery_expired', {
|
|
event_name: event.event_name,
|
|
admin_email: event.admin_email
|
|
});
|
|
|
|
// Start archiving process
|
|
await archiveEvent(event);
|
|
|
|
logger.info(`Handled expiration for event ${event.slug}`);
|
|
} catch (error) {
|
|
logger.error(`Error handling expired event ${event.slug}:`, error);
|
|
}
|
|
}
|
|
|
|
module.exports = { startExpirationChecker };
|