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 jwt = require('jsonwebtoken');
const { User } = require('../models');
const config = require('../config/config');
// Generate JWT token
const generateToken = (userId) => {
return jwt.sign(
{ userId },
config.jwt.secret,
{ expiresIn: config.jwt.expiresIn }
);
};
// Generate refresh token
const generateRefreshToken = (userId) => {
return jwt.sign(
{ userId, type: 'refresh' },
config.jwt.refreshSecret,
{ expiresIn: config.jwt.refreshExpiresIn }
);
};
// Verify JWT token
const verifyToken = (token) => {
try {
return jwt.verify(token, config.jwt.secret);
} catch (error) {
throw new Error('Invalid token');
}
};
// Verify refresh token
const verifyRefreshToken = (token) => {
try {
const decoded = jwt.verify(token, config.jwt.refreshSecret);
if (decoded.type !== 'refresh') {
throw new Error('Invalid refresh token');
}
return decoded;
} catch (error) {
throw new Error('Invalid refresh token');
}
};
// Authentication middleware
const authenticate = async (req, res, next) => {
try {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({
success: false,
message: 'Access token is required',
});
}
const token = authHeader.startsWith('Bearer ')
? authHeader.slice(7)
: authHeader;
if (!token) {
return res.status(401).json({
success: false,
message: 'Access token is required',
});
}
const decoded = verifyToken(token);
const user = await User.findActiveById(decoded.userId);
if (!user) {
return res.status(401).json({
success: false,
message: 'User not found or inactive',
});
}
// Update last login
user.last_login = new Date();
await user.save();
req.user = user;
next();
} catch (error) {
console.error('Authentication error:', error);
if (error.name === 'JsonWebTokenError') {
return res.status(401).json({
success: false,
message: 'Invalid token',
});
}
if (error.name === 'TokenExpiredError') {
return res.status(401).json({
success: false,
message: 'Token expired',
});
}
return res.status(401).json({
success: false,
message: 'Authentication failed',
});
}
};
// Optional authentication middleware (doesn't fail if no token)
const optionalAuth = async (req, res, next) => {
try {
const authHeader = req.headers.authorization;
if (!authHeader) {
req.user = null;
return next();
}
const token = authHeader.startsWith('Bearer ')
? authHeader.slice(7)
: authHeader;
if (!token) {
req.user = null;
return next();
}
const decoded = verifyToken(token);
const user = await User.findActiveById(decoded.userId);
req.user = user || null;
next();
} catch (error) {
// If token is invalid, just continue without user
req.user = null;
next();
}
};
// Check if user owns the resource
const checkResourceOwnership = (resourceUserIdField = 'user_id') => {
return async (req, res, next) => {
try {
const resourceId = req.params.id || req.params.meetingId || req.params.recordingId || req.params.noteId;
let resource;
// Determine resource type and fetch it
if (req.params.meetingId || req.baseUrl.includes('/meetings')) {
const { Meeting } = require('../models');
resource = await Meeting.findByPk(resourceId || req.params.meetingId);
} else if (req.params.recordingId || req.baseUrl.includes('/recordings')) {
const { Recording } = require('../models');
resource = await Recording.findByPk(resourceId || req.params.recordingId);
// For recordings, check meeting ownership
if (resource) {
const { Meeting } = require('../models');
const meeting = await Meeting.findByPk(resource.meeting_id);
resource = meeting;
}
} else if (req.params.noteId || req.baseUrl.includes('/notes')) {
const { Note } = require('../models');
resource = await Note.findByPk(resourceId || req.params.noteId);
} else if (req.params.id && req.baseUrl.includes('/transcripts')) {
const { Transcript } = require('../models');
resource = await Transcript.findByPk(req.params.id);
// For transcripts, check recording ownership
if (resource) {
const { Recording } = require('../models');
const recording = await Recording.findByPk(resource.recording_id);
if (recording) {
const { Meeting } = require('../models');
const meeting = await Meeting.findByPk(recording.meeting_id);
resource = meeting;
}
}
} else if (req.params.id && req.baseUrl.includes('/summaries')) {
const { Summary } = require('../models');
resource = await Summary.findByPk(req.params.id);
// For summaries, check meeting ownership
if (resource) {
const { Meeting } = require('../models');
const meeting = await Meeting.findByPk(resource.meeting_id);
resource = meeting;
}
}
if (!resource) {
return res.status(404).json({
success: false,
message: 'Resource not found',
});
}
const resourceUserId = resource[resourceUserIdField];
if (!resourceUserId || resourceUserId !== req.user.id) {
return res.status(403).json({
success: false,
message: 'Access denied: You can only access your own resources',
});
}
// Store the resource for use in subsequent middleware
req.resource = resource;
next();
} catch (error) {
console.error('Resource ownership check error:', error);
return res.status(500).json({
success: false,
message: 'Internal server error',
});
}
};
};
// Check if user has specific role (for future role-based access)
const requireRole = (roles) => {
return (req, res, next) => {
if (!req.user) {
return res.status(401).json({
success: false,
message: 'Authentication required',
});
}
const userRole = req.user.role || 'user';
const allowedRoles = Array.isArray(roles) ? roles : [roles];
if (!allowedRoles.includes(userRole)) {
return res.status(403).json({
success: false,
message: 'Insufficient permissions',
});
}
next();
};
};
// Rate limiting per user
const userRateLimit = (maxRequests = 100, windowMs = 15 * 60 * 1000) => {
const userRequests = new Map();
return (req, res, next) => {
if (!req.user) {
return next();
}
const userId = req.user.id;
const now = Date.now();
const windowStart = now - windowMs;
// Clean old entries
if (userRequests.has(userId)) {
const requests = userRequests.get(userId);
const validRequests = requests.filter(time => time > windowStart);
userRequests.set(userId, validRequests);
}
// Check current requests
const currentRequests = userRequests.get(userId) || [];
if (currentRequests.length >= maxRequests) {
return res.status(429).json({
success: false,
message: 'Too many requests, please try again later',
retryAfter: Math.ceil(windowMs / 1000),
});
}
// Add current request
currentRequests.push(now);
userRequests.set(userId, currentRequests);
next();
};
};
module.exports = {
generateToken,
generateRefreshToken,
verifyToken,
verifyRefreshToken,
authenticate,
optionalAuth,
checkResourceOwnership,
requireRole,
userRateLimit,
}; |
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0073 ]-- |