hotfix: Security, performance, and code cleanup

- Remove hardcoded database password fallback
- Add encryption salt validation (min 32 chars)
- Separate EMAIL_ENCRYPTION_KEY from JWT_SECRET
- Fix command injection in status.service.js (use execFileSync)
- Remove unnecessary SQL injection regex middleware
- Create shared utilities (queryBuilder, pagination, emailAccountHelper)
- Fix N+1 query problems in contact and todo services
- Merge duplicate JMAP config functions
- Add database indexes migration
- Standardize error responses with error codes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
richardtekula
2026-01-19 07:17:23 +01:00
parent 0523087961
commit 73a3c6bf95
15 changed files with 278 additions and 114 deletions

View File

@@ -1,6 +1,7 @@
import os from 'os';
import path from 'path';
import { execSync } from 'child_process';
import { execFileSync } from 'child_process';
import fs from 'fs';
import { pool } from '../config/database.js';
/**
@@ -31,7 +32,7 @@ const getCpuUsage = () => {
const getMemoryUsage = () => {
try {
// Read /proc/meminfo for accurate memory stats (like htop)
const meminfo = execSync('cat /proc/meminfo', { encoding: 'utf8' });
const meminfo = fs.readFileSync('/proc/meminfo', 'utf8');
const lines = meminfo.split('\n');
const getValue = (key) => {
@@ -79,8 +80,9 @@ const getMemoryUsage = () => {
*/
const getDiskUsage = () => {
try {
const output = execSync('df -BG / | tail -1', { encoding: 'utf8' });
const parts = output.trim().split(/\s+/);
const output = execFileSync('df', ['-BG', '/'], { encoding: 'utf8' });
const lines = output.trim().split('\n');
const parts = lines[lines.length - 1].split(/\s+/);
const totalGB = parseInt(parts[1]) || 0;
const usedGB = parseInt(parts[2]) || 0;
@@ -118,7 +120,7 @@ const getBackendStats = () => {
const getUploadsSize = () => {
try {
const uploadsPath = path.join(process.cwd(), 'uploads');
const output = execSync(`du -sm "${uploadsPath}" 2>/dev/null || echo "0"`, { encoding: 'utf8' });
const output = execFileSync('du', ['-sm', uploadsPath], { encoding: 'utf8' });
const sizeMB = parseInt(output.split('\t')[0]) || 0;
return {