All checks were successful
continuous-integration/drone/push Build is passing
✨ New Features: - Dynamic permission-based context menus for files and folders - Support for collaborative folder access control - Upload to specific folders including shared folders - Changelog modal for version updates - Improved dark mode synchronization 🐛 Bug Fixes: - Fixed context menu displaying incorrect options - Fixed CSS !important override preventing dynamic menu behavior - Fixed folder collaboration permission checks - Fixed breadcrumb navigation with empty segments - Fixed "Premature close" error loop in attachments - Fixed missing user variable in admin routes - Fixed avatar loading COEP policy issues 🔒 Security: - Added security middleware (CSRF, rate limiting, input validation) - Fixed collaboration folder access validation - Improved shared folder permission handling 🎨 UI/UX Improvements: - Removed Actions column from folder view - Context menu now properly hides/shows based on permissions - Better visual feedback for collaborative folders - Improved upload flow with inline modals 🧹 Code Quality: - Added collaboration data to folder routes - Refactored context menu logic for better maintainability - Added debug logging for troubleshooting - Improved file upload handling with chunking support
198 lines
5.8 KiB
JavaScript
198 lines
5.8 KiB
JavaScript
require('dotenv').config();
|
|
const express = require('express');
|
|
const session = require('express-session');
|
|
const passport = require('passport');
|
|
const bodyParser = require('body-parser');
|
|
const path = require('path');
|
|
const flash = require('connect-flash');
|
|
const crypto = require('crypto');
|
|
const fs = require('fs').promises;
|
|
const cron = require('node-cron');
|
|
const chalk = require('chalk');
|
|
|
|
// Import des services et configurations
|
|
const { logger, logRequestInfo, ErrorLogger } = require('./config/logs');
|
|
const { version } = require('./package.json');
|
|
const routes = require('./routes/routes.js');
|
|
const fileCleanup = require('./services/fileCleanupService');
|
|
const reportManager = require('./services/reportService.js');
|
|
|
|
// Import des middlewares de sécurité
|
|
const securityHeadersMiddleware = require('./Middlewares/securityHeadersMiddleware');
|
|
const { inputValidationMiddleware } = require('./Middlewares/inputValidationMiddleware');
|
|
const { generalLimiter } = require('./Middlewares/rateLimitMiddleware');
|
|
|
|
// Configuration de l'application
|
|
const app = express();
|
|
const PORT = process.env.PORT || 5053;
|
|
|
|
// Import des modèles requis
|
|
require('./models/fileCreated.js');
|
|
|
|
// Lecture du fichier de configuration
|
|
const loadSetup = async () => {
|
|
try {
|
|
const setupPath = path.join(__dirname, 'data', 'setup.json');
|
|
const setupData = await fs.readFile(setupPath, 'utf8');
|
|
return JSON.parse(setupData);
|
|
} catch (err) {
|
|
logger.error('Error reading setup.json:', err);
|
|
return {};
|
|
}
|
|
};
|
|
|
|
// Configuration de l'application
|
|
const configureApp = async () => {
|
|
const setup = await loadSetup();
|
|
const WebSocketManager = require('./models/websocketManager.js');
|
|
|
|
// Configuration des stratégies d'authentification
|
|
if (setup.discord) require('./models/Passport-Discord.js');
|
|
if (setup.ldap) require('./models/Passport-ActiveDirectory.js');
|
|
|
|
// Middleware de base
|
|
app.set('trust proxy', 1);
|
|
app.set('view engine', 'ejs');
|
|
app.set('views', path.join(__dirname, 'views'));
|
|
|
|
// Gestionnaire de favicon.ico
|
|
app.get('/favicon.ico', (req, res) => {
|
|
res.status(204).end();
|
|
});
|
|
|
|
// Protection des fichiers sensibles
|
|
app.get(['/data/user.json', '/data/file_info.json', '/data/setup.json'],
|
|
(req, res) => res.status(403).json({ error: 'Access Denied' }));
|
|
|
|
// Configuration des middlewares
|
|
// Désactiver le header X-Powered-By
|
|
app.disable('x-powered-by');
|
|
|
|
// Middlewares de sécurité
|
|
app.use(securityHeadersMiddleware);
|
|
app.use(generalLimiter);
|
|
app.use(inputValidationMiddleware);
|
|
|
|
app.use(express.static(path.join(__dirname, 'public')));
|
|
app.use('/public', express.static(path.join(__dirname, 'public')));
|
|
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
|
|
app.use(bodyParser.json({ limit: '10mb' }));
|
|
app.use(session({
|
|
secret: crypto.randomBytes(64).toString('hex'),
|
|
resave: false,
|
|
saveUninitialized: false, // Plus sécurisé
|
|
name: 'sessionId', // Nom personnalisé pour ne pas révéler la stack
|
|
cookie: {
|
|
secure: process.env.NODE_ENV === 'production',
|
|
httpOnly: true, // Protection XSS
|
|
maxAge: 24 * 60 * 60 * 1000,
|
|
sameSite: 'strict' // Protection CSRF
|
|
}
|
|
}));
|
|
app.use(passport.initialize());
|
|
app.use(passport.session());
|
|
app.use(flash());
|
|
app.use(logRequestInfo);
|
|
app.use(routes);
|
|
|
|
app.use((req, res, next) => {
|
|
if (req.accepts('html')) {
|
|
res.status(404).render('unauthorized', { url: req.url });
|
|
} else {
|
|
// Pour les requêtes API ou autres
|
|
res.status(404).json({ error: 'Not Found' });
|
|
}
|
|
});
|
|
|
|
app.use((err, req, res, next) => {
|
|
ErrorLogger.error('Unhandled error:', err);
|
|
|
|
res.status(500).json({ error: 'Internal Server Error', message: err.message });
|
|
});
|
|
};
|
|
|
|
process.removeAllListeners('warning');
|
|
process.on('warning', (warning) => {
|
|
if (warning.name === 'DeprecationWarning' && warning.message.includes('punycode')) {
|
|
return;
|
|
}
|
|
console.warn(warning.name, warning.message);
|
|
});
|
|
|
|
// Configuration des tâches planifiées
|
|
const configureCronJobs = () => {
|
|
|
|
// Service de nettoyage des fichiers
|
|
fileCleanup.start();
|
|
|
|
// Service de rreport système
|
|
reportManager.start();
|
|
};
|
|
|
|
// Utilitaires pour la vérification des fichiers
|
|
const fileUtils = {
|
|
async fileExists(filePath) {
|
|
try {
|
|
await fs.access(filePath);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Démarrage du serveur
|
|
const startServer = () => {
|
|
const server = app.listen(PORT, () => {
|
|
server.timeout = 300000;
|
|
console.clear()
|
|
|
|
if (logger) {
|
|
logger.info('☀️ Welcome to the Content Delivery Network Server');
|
|
logger.info(`🚀 Server running on port ${PORT}`);
|
|
logger.info(`⚜️ Application developed by Dinawo, part of the Myaxrin Labs group`);
|
|
logger.info(`♨️ Version: ${version}`);
|
|
} else {
|
|
console.error('🔴 Logger is not initialized');
|
|
}
|
|
});
|
|
|
|
// Initialiser le WebSocket Manager ici, après la création du serveur
|
|
const WebSocketManager = require('./models/websocketManager.js');
|
|
const wsManager = new WebSocketManager(server);
|
|
app.set('wsManager', wsManager);
|
|
|
|
return server;
|
|
};
|
|
|
|
// Gestion des erreurs globales
|
|
const configureErrorHandling = () => {
|
|
process.on('uncaughtException', (err) => {
|
|
ErrorLogger.error('Uncaught Exception:', err);
|
|
});
|
|
|
|
process.on('unhandledRejection', (reason, promise) => {
|
|
ErrorLogger.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
});
|
|
};
|
|
|
|
// Initialisation de l'application
|
|
const initializeApp = async () => {
|
|
try {
|
|
configureErrorHandling();
|
|
await configureApp();
|
|
configureCronJobs();
|
|
const server = startServer();
|
|
|
|
return server;
|
|
} catch (err) {
|
|
logger.error('Failed to initialize application:', err);
|
|
process.exit(1);
|
|
}
|
|
};
|
|
|
|
// Démarrage de l'application
|
|
initializeApp();
|
|
|
|
// Export pour les tests
|
|
module.exports = { app, fileUtils }; |