Initial LinkedSign platform
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
const rateLimit = require('express-rate-limit');
|
||||
|
||||
const authRateLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000,
|
||||
max: 20,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
message: {
|
||||
success: false,
|
||||
data: null,
|
||||
error: 'Too many login attempts. Please try again later.',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = authRateLimiter;
|
||||
@@ -0,0 +1,19 @@
|
||||
const { verify } = require('../utils/jwt');
|
||||
|
||||
const authenticate = (req, res, next) => {
|
||||
const authHeader = req.headers['authorization'];
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
return res.status(401).json({ success: false, data: null, error: 'Authorization token required.' });
|
||||
}
|
||||
|
||||
const token = authHeader.slice(7);
|
||||
try {
|
||||
const decoded = verify(token);
|
||||
req.user = { id: decoded.sub, email: decoded.email, role: decoded.role, name: decoded.name };
|
||||
return next();
|
||||
} catch {
|
||||
return res.status(401).json({ success: false, data: null, error: 'Invalid or expired token.' });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = authenticate;
|
||||
@@ -0,0 +1,29 @@
|
||||
const { sendError } = require('../utils/apiResponse');
|
||||
|
||||
const errorHandler = (err, req, res, next) => {
|
||||
if (res.headersSent) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
const statusCode = err.statusCode || 500;
|
||||
if (statusCode >= 500) {
|
||||
console.error(`[ERROR ${statusCode}]`, err.message);
|
||||
console.error(err.stack?.split('\n').slice(0, 6).join('\n'));
|
||||
}
|
||||
const message = err.code
|
||||
? (err.message || 'Request error')
|
||||
: (statusCode >= 500 ? 'Internal server error' : err.message || 'Request error');
|
||||
|
||||
if (err.code) {
|
||||
return res.status(statusCode).json({
|
||||
success: false,
|
||||
data: err.data || null,
|
||||
error: message,
|
||||
code: err.code,
|
||||
});
|
||||
}
|
||||
|
||||
return sendError(res, message, statusCode);
|
||||
};
|
||||
|
||||
module.exports = errorHandler;
|
||||
@@ -0,0 +1,28 @@
|
||||
const path = require('path');
|
||||
|
||||
const MAX_FILE_SIZE = 10 * 1024 * 1024;
|
||||
|
||||
const fileValidator = (req, res, next) => {
|
||||
const file = req.file;
|
||||
|
||||
if (!file) {
|
||||
const error = new Error('Invalid file upload');
|
||||
error.statusCode = 400;
|
||||
return next(error);
|
||||
}
|
||||
|
||||
const extension = path.extname(file.originalname || '').toLowerCase();
|
||||
const isPdfMimeType = file.mimetype === 'application/pdf';
|
||||
const isPdfExtension = extension === '.pdf';
|
||||
const isValidSize = typeof file.size === 'number' && file.size <= MAX_FILE_SIZE;
|
||||
|
||||
if (!isPdfMimeType || !isPdfExtension || !isValidSize) {
|
||||
const error = new Error('Invalid file upload');
|
||||
error.statusCode = 400;
|
||||
return next(error);
|
||||
}
|
||||
|
||||
return next();
|
||||
};
|
||||
|
||||
module.exports = fileValidator;
|
||||
@@ -0,0 +1,7 @@
|
||||
const { sendError } = require('../utils/apiResponse');
|
||||
|
||||
const notFound = (req, res) => {
|
||||
return sendError(res, `Route not found: ${req.method} ${req.originalUrl}`, 404);
|
||||
};
|
||||
|
||||
module.exports = notFound;
|
||||
Reference in New Issue
Block a user