feat: Enhance server security and performance by adding helmet for security headers, implementing rate limiting, and centralizing error handling; update frontend API calls to use a dedicated api module for consistency
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 4m37s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 4m37s
This commit is contained in:
+31
-3
@@ -8,11 +8,27 @@ const compression = require('compression');
|
||||
const Ajv = require('ajv');
|
||||
const net = require('net');
|
||||
const crypto = require('crypto');
|
||||
const helmet = require('helmet');
|
||||
const rateLimit = require('express-rate-limit');
|
||||
|
||||
const app = express();
|
||||
const port = 3001;
|
||||
const port = Number(process.env.PORT) || 3001;
|
||||
|
||||
// CORS: при необходимости сузьте до списка доменов (пример ниже)
|
||||
// const allowed = (process.env.CORS_ORIGINS || '').split(',').map(s => s.trim()).filter(Boolean);
|
||||
// app.use(cors({ origin: (origin, cb) => { if (!origin || allowed.length===0 || allowed.includes(origin)) return cb(null, true); cb(new Error('CORS blocked')); }, credentials: true }));
|
||||
app.use(cors());
|
||||
app.use(helmet({
|
||||
crossOriginResourcePolicy: { policy: 'cross-origin' },
|
||||
}));
|
||||
app.disable('x-powered-by');
|
||||
const limiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 1000,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
app.use(limiter);
|
||||
app.use(express.json());
|
||||
app.use(compression());
|
||||
// Disable Express auto-ETag to avoid weak ETags on JSON bodies
|
||||
@@ -24,6 +40,8 @@ app.use((req, res, next) => {
|
||||
next();
|
||||
});
|
||||
|
||||
// Централизованный обработчик ошибок (должен быть подключён ПОСЛЕ роутов — см. ниже второе use)
|
||||
|
||||
// Helpers: meta and responses
|
||||
function toIso(x) {
|
||||
try { return new Date(x).toISOString(); } catch { return null; }
|
||||
@@ -1739,6 +1757,16 @@ app.get('*', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
||||
});
|
||||
|
||||
// Централизованный error handler (последний middleware)
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
app.use((err, req, res, next) => {
|
||||
const status = typeof err?.status === 'number' ? err.status : 500;
|
||||
const code = err?.code || 'E_INTERNAL';
|
||||
const message = status === 500 && process.env.NODE_ENV === 'production' ? 'Internal Server Error' : (err?.message || 'Error');
|
||||
try { console.error('error:', err); } catch {}
|
||||
res.status(status).json({ message, code });
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running on http://localhost:${port}`);
|
||||
});
|
||||
console.log(`Server is running on http://localhost:${port}`);
|
||||
});
|
||||
Reference in New Issue
Block a user