Initial commit - Project start (July 17, 2025)
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
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 <[email protected]>
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* SQL Security Utilities
|
||||
* Provides safe methods for handling user input in SQL queries
|
||||
*/
|
||||
|
||||
/**
|
||||
* Validate and sanitize days parameter for date range queries
|
||||
* @param {any} days - The days parameter from user input
|
||||
* @returns {number} Safe integer between 1 and 365
|
||||
*/
|
||||
function sanitizeDays(days) {
|
||||
const parsed = parseInt(days);
|
||||
|
||||
// Check if it's a valid number
|
||||
if (isNaN(parsed)) {
|
||||
return 7; // Default to 7 days
|
||||
}
|
||||
|
||||
// Ensure it's within reasonable bounds
|
||||
if (parsed < 1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (parsed > 365) {
|
||||
return 365; // Maximum 1 year
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape special characters in LIKE queries
|
||||
* @param {string} input - The search string from user input
|
||||
* @returns {string} Escaped string safe for LIKE queries
|
||||
*/
|
||||
function escapeLikePattern(input) {
|
||||
if (!input || typeof input !== 'string') {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Escape special LIKE pattern characters
|
||||
// In SQL LIKE patterns:
|
||||
// % matches any sequence of characters
|
||||
// _ matches any single character
|
||||
// \ is the escape character
|
||||
return input
|
||||
.replace(/\\/g, '\\\\') // Escape backslashes first
|
||||
.replace(/%/g, '\\%') // Escape percent signs
|
||||
.replace(/_/g, '\\_') // Escape underscores
|
||||
.replace(/'/g, '\'\''); // Escape single quotes for safety
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a safe date range condition using Knex
|
||||
* @param {object} query - Knex query builder instance
|
||||
* @param {string} column - The timestamp column name
|
||||
* @param {number} days - Number of days to go back
|
||||
* @returns {object} Modified query with safe date range condition
|
||||
*/
|
||||
function addDateRangeCondition(query, column, days) {
|
||||
const safeDays = sanitizeDays(days);
|
||||
const startDate = new Date();
|
||||
startDate.setDate(startDate.getDate() - safeDays);
|
||||
|
||||
// Use Knex's built-in date comparison which handles parameterization
|
||||
return query.where(column, '>=', startDate.toISOString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a safe LIKE condition using Knex
|
||||
* @param {object} query - Knex query builder instance
|
||||
* @param {string} column - The column to search
|
||||
* @param {string} pattern - The search pattern
|
||||
* @returns {object} Modified query with safe LIKE condition
|
||||
*/
|
||||
function addLikeCondition(query, column, pattern) {
|
||||
if (!pattern || typeof pattern !== 'string') {
|
||||
return query;
|
||||
}
|
||||
|
||||
const escapedPattern = escapeLikePattern(pattern);
|
||||
// Knex handles parameterization of the LIKE value
|
||||
return query.where(column, 'like', `%${escapedPattern}%`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate sort column against whitelist
|
||||
* @param {string} column - The column name to sort by
|
||||
* @param {string[]} allowedColumns - Array of allowed column names
|
||||
* @param {string} defaultColumn - Default column if invalid
|
||||
* @returns {string} Safe column name
|
||||
*/
|
||||
function validateSortColumn(column, allowedColumns, defaultColumn) {
|
||||
if (!column || !allowedColumns.includes(column)) {
|
||||
return defaultColumn;
|
||||
}
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate sort order
|
||||
* @param {string} order - The sort order (asc/desc)
|
||||
* @returns {string} Safe sort order
|
||||
*/
|
||||
function validateSortOrder(order) {
|
||||
const lowerOrder = (order || '').toLowerCase();
|
||||
return lowerOrder === 'asc' ? 'asc' : 'desc';
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sanitizeDays,
|
||||
escapeLikePattern,
|
||||
addDateRangeCondition,
|
||||
addLikeCondition,
|
||||
validateSortColumn,
|
||||
validateSortOrder
|
||||
};
|
||||
Reference in New Issue
Block a user