Initial commit: StreamFlow IPTV platform
This commit is contained in:
commit
73a8ae9ffd
1240 changed files with 278451 additions and 0 deletions
129
backend/middleware/auth.js
Normal file
129
backend/middleware/auth.js
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
const jwt = require('jsonwebtoken');
|
||||
const logger = require('../utils/logger');
|
||||
const db = require('../database/db').db;
|
||||
const { SESSION_POLICY } = require('../utils/passwordPolicy');
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'change_this_in_production';
|
||||
|
||||
const authenticate = (req, res, next) => {
|
||||
// Check Authorization header first, then query parameter
|
||||
let token = req.headers.authorization?.split(' ')[1];
|
||||
|
||||
if (!token && req.query.token) {
|
||||
token = req.query.token;
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
logger.info('[AUTH] No token provided');
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
}
|
||||
|
||||
// CWE-532: Do not log tokens or token details - they are credentials
|
||||
logger.info('[AUTH] Verifying authentication token');
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, JWT_SECRET);
|
||||
logger.info(`[AUTH] Token verified for user ${decoded.userId}`);
|
||||
|
||||
// Check session activity and idle timeout
|
||||
db.get(
|
||||
'SELECT * FROM active_sessions WHERE session_token = ? AND user_id = ?',
|
||||
[token, decoded.userId],
|
||||
(err, session) => {
|
||||
if (err) {
|
||||
logger.error('Session check error:', err);
|
||||
return res.status(500).json({ error: 'Session validation failed' });
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
logger.info('[AUTH] Session not found for token in database');
|
||||
return res.status(401).json({ error: 'Session not found or expired', sessionExpired: true });
|
||||
}
|
||||
|
||||
logger.info('[AUTH] Session found, checking expiry');
|
||||
|
||||
// Check if session has expired (absolute timeout)
|
||||
const now = new Date();
|
||||
const expiresAt = new Date(session.expires_at);
|
||||
|
||||
if (now >= expiresAt) {
|
||||
// Delete expired session
|
||||
db.run('DELETE FROM active_sessions WHERE id = ?', [session.id]);
|
||||
return res.status(401).json({ error: 'Session expired', sessionExpired: true });
|
||||
}
|
||||
|
||||
// Check idle timeout (2 hours by default)
|
||||
const lastActivity = new Date(session.last_activity);
|
||||
const idleTimeMs = now - lastActivity;
|
||||
const idleTimeoutMs = SESSION_POLICY.idleTimeout * 60 * 60 * 1000; // Convert hours to ms
|
||||
|
||||
if (idleTimeMs > idleTimeoutMs) {
|
||||
// Session idle for too long - terminate it
|
||||
db.run('DELETE FROM active_sessions WHERE id = ?', [session.id]);
|
||||
logger.info(`Session ${session.id} terminated due to idle timeout (${idleTimeMs}ms idle)`);
|
||||
return res.status(401).json({ error: 'Session expired due to inactivity', sessionExpired: true });
|
||||
}
|
||||
|
||||
// Update last activity
|
||||
db.run(
|
||||
'UPDATE active_sessions SET last_activity = ? WHERE id = ?',
|
||||
[now.toISOString(), session.id],
|
||||
(updateErr) => {
|
||||
if (updateErr) {
|
||||
logger.error('Failed to update session activity:', updateErr);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
req.user = decoded;
|
||||
req.sessionId = session.id;
|
||||
next();
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error('Authentication error:', error);
|
||||
logger.error(`[AUTH] JWT Verification Failed: ${error.name} - ${error.message}`);
|
||||
|
||||
// Provide more specific error messages
|
||||
let errorMessage = 'Invalid or expired token';
|
||||
if (error.name === 'TokenExpiredError') {
|
||||
errorMessage = 'Token has expired';
|
||||
} else if (error.name === 'JsonWebTokenError') {
|
||||
errorMessage = 'Invalid token';
|
||||
}
|
||||
|
||||
res.status(401).json({
|
||||
error: errorMessage,
|
||||
sessionExpired: true // This triggers automatic logout on frontend
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const authorize = (...roles) => {
|
||||
return (req, res, next) => {
|
||||
if (!req.user) {
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
}
|
||||
|
||||
if (!roles.includes(req.user.role)) {
|
||||
return res.status(403).json({ error: 'Insufficient permissions' });
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
// Convenience middleware for admin-only routes
|
||||
const requireAdmin = (req, res, next) => {
|
||||
if (!req.user) {
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
}
|
||||
|
||||
if (req.user.role !== 'admin') {
|
||||
return res.status(403).json({ error: 'Admin access required' });
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
module.exports = { authenticate, authorize, requireAdmin };
|
||||
Loading…
Add table
Add a link
Reference in a new issue