Software: Apache. PHP/8.1.30 uname -a: Linux server1.tuhinhossain.com 5.15.0-163-generic #173-Ubuntu SMP Tue Oct 14 17:51:00 UTC uid=1002(picotech) gid=1003(picotech) groups=1003(picotech),0(root) Safe-mode: OFF (not secure) /home/picotech/domains/note.picotech.app/public_html/src/middleware/ drwxr-xr-x | |
| Viewing file: Select action/file-type: const config = require('../config/config');
// Sanitize error messages to prevent information disclosure
const sanitizeErrorMessage = (message) => {
if (!message) return 'An error occurred';
// Remove file paths, stack traces, and sensitive information
return message
.replace(/\/[^\s]+/g, '/[REDACTED]') // Remove file paths
.replace(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g, '[REDACTED_IP]') // Remove IPs
.replace(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, '[REDACTED_EMAIL]') // Remove emails
.replace(/\b[A-Z]{2,}\b/g, '[REDACTED_TOKEN]') // Remove potential tokens/keys
.replace(/password|token|key|secret/gi, '[REDACTED]') // Remove sensitive keywords
.substring(0, 200); // Limit length
};
// Custom error class
class AppError extends Error {
constructor(message, statusCode, code = null, details = null) {
super(message);
this.statusCode = statusCode;
this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
this.isOperational = true;
this.code = code;
this.details = details;
Error.captureStackTrace(this, this.constructor);
}
}
// Handle Sequelize validation errors
const handleSequelizeValidationError = (err) => {
const errors = err.errors.map(error => ({
field: error.path,
message: error.message,
value: error.value,
}));
return new AppError('Validation failed', 400, 'VALIDATION_ERROR', errors);
};
// Handle Sequelize unique constraint errors
const handleSequelizeUniqueConstraintError = (err) => {
const field = err.errors[0]?.path || 'field';
const message = `${field} already exists`;
return new AppError(message, 409, 'DUPLICATE_ENTRY');
};
// Handle Sequelize foreign key constraint errors
const handleSequelizeForeignKeyConstraintError = (err) => {
return new AppError('Referenced resource not found', 400, 'FOREIGN_KEY_CONSTRAINT');
};
// Handle JWT errors
const handleJWTError = () => {
return new AppError('Invalid token. Please log in again', 401, 'INVALID_TOKEN');
};
const handleJWTExpiredError = () => {
return new AppError('Your token has expired. Please log in again', 401, 'TOKEN_EXPIRED');
};
// Handle Multer errors
const handleMulterError = (err) => {
if (err.code === 'LIMIT_FILE_SIZE') {
return new AppError('File too large', 400, 'FILE_TOO_LARGE');
}
if (err.code === 'LIMIT_FILE_COUNT') {
return new AppError('Too many files', 400, 'TOO_MANY_FILES');
}
if (err.code === 'LIMIT_UNEXPECTED_FILE') {
return new AppError('Unexpected file field', 400, 'UNEXPECTED_FILE');
}
return new AppError('File upload error', 400, 'UPLOAD_ERROR');
};
// Send error response in development
const sendErrorDev = (err, res) => {
res.status(err.statusCode).json({
success: false,
error: {
status: err.status,
message: err.message,
code: err.code,
stack: err.stack,
details: err.details || null,
},
});
};
// Send error response in development with validation details
const sendValidationErrorDev = (err, res) => {
res.status(err.statusCode).json({
success: false,
error: {
status: err.status,
message: err.message,
code: err.code,
details: err.details || null,
stack: err.stack,
},
});
};
// Send error response in production
const sendErrorProd = (err, res) => {
// Operational, trusted error: send message to client
if (err.isOperational) {
res.status(err.statusCode).json({
success: false,
error: {
status: err.status,
message: err.message,
code: err.code,
stack: undefined, // Never include stack in production
details: err.details || null,
},
});
} else {
// Programming or other unknown error: don't leak error details
// Log full error details for debugging but sanitize response
console.error('ERROR 💥', {
message: sanitizeErrorMessage(err.message),
stack: undefined, // Never log stack traces in production
name: err.name,
// Don't log sensitive information like file paths, internal data
});
res.status(500).json({
success: false,
error: {
status: 'error',
message: 'Something went wrong!',
code: 'INTERNAL_SERVER_ERROR',
stack: undefined,
details: null,
},
});
}
};
// Main error handling middleware
const globalErrorHandler = (err, req, res, next) => {
err.statusCode = err.statusCode || 500;
err.status = err.status || 'error';
if (config.nodeEnv === 'development') {
sendErrorDev(err, res);
} else {
let error = { ...err };
error.message = err.message;
// Handle specific error types
if (err.name === 'SequelizeValidationError') {
error = handleSequelizeValidationError(error);
}
if (err.name === 'SequelizeUniqueConstraintError') {
error = handleSequelizeUniqueConstraintError(error);
}
if (err.name === 'SequelizeForeignKeyConstraintError') {
error = handleSequelizeForeignKeyConstraintError(error);
}
if (err.name === 'JsonWebTokenError') {
error = handleJWTError();
}
if (err.name === 'TokenExpiredError') {
error = handleJWTExpiredError();
}
if (err.name === 'MulterError') {
error = handleMulterError(err);
}
// Handle Sequelize database errors (like constraint violations)
if (err.name === 'SequelizeDatabaseError' || err.original?.code) {
// Handle specific database constraint errors
if (err.original?.code === 'ER_DUP_ENTRY') {
// Check if it's an email validation error (email format)
if (err.original?.sqlMessage?.includes('email')) {
error = new AppError('Invalid email address', 400, 'VALIDATION_ERROR', [{
field: 'email',
message: 'Invalid email address',
value: err.original?.sqlMessage?.match(/'([^']+)'/)?.[1] || 'invalid'
}]);
} else {
error = new AppError('A database constraint was violated. Please check your input.', 400, 'DATABASE_CONSTRAINT_ERROR');
}
} else {
error = new AppError('A database error occurred. Please try again.', 500, 'DATABASE_ERROR');
}
}
// Always send validation errors in development mode with details
if (err.code === 'VALIDATION_ERROR' && config.nodeEnv === 'development') {
sendValidationErrorDev(err, res);
} else {
sendErrorProd(error, res);
}
}
};
// Handle unhandled routes
const handleNotFound = (req, res, next) => {
const err = new AppError(`Can't find ${req.originalUrl} on this server!`, 404, 'ROUTE_NOT_FOUND');
next(err);
};
// Async error wrapper
const catchAsync = (fn) => {
return (req, res, next) => {
fn(req, res, next).catch(next);
};
};
// Handle unhandled promise rejections
const handleUnhandledRejection = () => {
process.on('unhandledRejection', (err, promise) => {
console.log('UNHANDLED REJECTION! 💥 Shutting down...');
console.log(err.name, err.message);
// Close server gracefully
process.exit(1);
});
};
// Handle uncaught exceptions
const handleUncaughtException = () => {
process.on('uncaughtException', (err) => {
console.log('UNCAUGHT EXCEPTION! 💥 Shutting down...');
console.log(err.name, err.message);
process.exit(1);
});
};
// Graceful shutdown handler
const handleGracefulShutdown = (server) => {
const shutdown = (signal) => {
console.log(`${signal} received. Shutting down gracefully...`);
server.close(() => {
console.log('Process terminated');
process.exit(0);
});
// Force close after 10 seconds
setTimeout(() => {
console.log('Forcing shutdown...');
process.exit(1);
}, 10000);
};
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
};
// Log error details
const logError = (err, req = null) => {
const errorInfo = {
timestamp: new Date().toISOString(),
message: config.nodeEnv === 'production' ? sanitizeErrorMessage(err.message) : err.message,
// Don't log stack traces in production to avoid information disclosure
stack: config.nodeEnv === 'development' ? err.stack : undefined,
statusCode: err.statusCode,
code: err.code,
};
if (req) {
errorInfo.request = {
method: req.method,
url: req.originalUrl,
// Sanitize IP address for privacy
ip: req.ip ? req.ip.replace(/\.\d+$/, '.***') : undefined,
userAgent: req.get('User-Agent') ? req.get('User-Agent').substring(0, 100) : undefined, // Limit user agent length
userId: req.user?.id || null,
};
}
console.error('Error Details:', JSON.stringify(errorInfo, null, 2));
};
// Validation error formatter
const formatValidationErrors = (errors) => {
return errors.map(error => ({
field: error.path || error.param,
message: error.msg || error.message,
value: error.value,
location: error.location,
}));
};
// Rate limit error handler
const handleRateLimitError = (req, res) => {
res.status(429).json({
success: false,
error: {
status: 'fail',
message: 'Too many requests from this IP, please try again later',
code: 'RATE_LIMIT_EXCEEDED',
stack: undefined,
details: { retryAfter: req.rateLimit?.resetTime || 900 },
},
});
};
module.exports = {
AppError,
globalErrorHandler,
handleNotFound,
catchAsync,
handleUnhandledRejection,
handleUncaughtException,
handleGracefulShutdown,
logError,
formatValidationErrors,
handleRateLimitError,
}; |
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0058 ]-- |