mirror of
https://github.com/9technologygroup/patchmon.net.git
synced 2025-11-12 01:45:57 +00:00
Refactored code to remove duplicate backend api endpoints for counting Improved connection persistence issues Improved database connection pooling issues Fixed redis connection efficiency Changed version to 1.3.0 Fixed GO binary detection based on package manager rather than OS
152 lines
4.0 KiB
JavaScript
152 lines
4.0 KiB
JavaScript
const jwt = require("jsonwebtoken");
|
|
const { getPrismaClient } = require("../config/prisma");
|
|
const {
|
|
validate_session,
|
|
update_session_activity,
|
|
is_tfa_bypassed,
|
|
} = require("../utils/session_manager");
|
|
|
|
const prisma = getPrismaClient();
|
|
|
|
// Middleware to verify JWT token with session validation
|
|
const authenticateToken = async (req, res, next) => {
|
|
try {
|
|
const authHeader = req.headers.authorization;
|
|
const token = authHeader?.split(" ")[1]; // Bearer TOKEN
|
|
|
|
if (!token) {
|
|
return res.status(401).json({ error: "Access token required" });
|
|
}
|
|
|
|
// Verify token
|
|
if (!process.env.JWT_SECRET) {
|
|
throw new Error("JWT_SECRET environment variable is required");
|
|
}
|
|
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
|
|
|
// Validate session and check inactivity timeout
|
|
const validation = await validate_session(decoded.sessionId, token);
|
|
|
|
if (!validation.valid) {
|
|
const error_messages = {
|
|
"Session not found": "Session not found",
|
|
"Session revoked": "Session has been revoked",
|
|
"Session expired": "Session has expired",
|
|
"Session inactive":
|
|
validation.message || "Session timed out due to inactivity",
|
|
"Token mismatch": "Invalid token",
|
|
"User inactive": "User account is inactive",
|
|
};
|
|
|
|
return res.status(401).json({
|
|
error: error_messages[validation.reason] || "Authentication failed",
|
|
reason: validation.reason,
|
|
});
|
|
}
|
|
|
|
// Update session activity timestamp
|
|
await update_session_activity(decoded.sessionId);
|
|
|
|
// Check if TFA is bypassed for this session
|
|
const tfa_bypassed = await is_tfa_bypassed(decoded.sessionId);
|
|
|
|
// Update last login (only on successful authentication)
|
|
await prisma.users.update({
|
|
where: { id: validation.user.id },
|
|
data: {
|
|
last_login: new Date(),
|
|
updated_at: new Date(),
|
|
},
|
|
});
|
|
|
|
req.user = validation.user;
|
|
req.session_id = decoded.sessionId;
|
|
req.tfa_bypassed = tfa_bypassed;
|
|
next();
|
|
} catch (error) {
|
|
if (error.name === "JsonWebTokenError") {
|
|
return res.status(401).json({ error: "Invalid token" });
|
|
}
|
|
if (error.name === "TokenExpiredError") {
|
|
return res.status(401).json({ error: "Token expired" });
|
|
}
|
|
console.error("Auth middleware error:", error);
|
|
return res.status(500).json({ error: "Authentication failed" });
|
|
}
|
|
};
|
|
|
|
// Middleware to check admin role
|
|
const requireAdmin = (req, res, next) => {
|
|
if (req.user.role !== "admin") {
|
|
return res.status(403).json({ error: "Admin access required" });
|
|
}
|
|
next();
|
|
};
|
|
|
|
// Middleware to check if user is authenticated (optional)
|
|
const optionalAuth = async (req, _res, next) => {
|
|
try {
|
|
const authHeader = req.headers.authorization;
|
|
const token = authHeader?.split(" ")[1];
|
|
|
|
if (token) {
|
|
if (!process.env.JWT_SECRET) {
|
|
throw new Error("JWT_SECRET environment variable is required");
|
|
}
|
|
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
|
const user = await prisma.users.findUnique({
|
|
where: { id: decoded.userId },
|
|
select: {
|
|
id: true,
|
|
username: true,
|
|
email: true,
|
|
role: true,
|
|
is_active: true,
|
|
last_login: true,
|
|
created_at: true,
|
|
updated_at: true,
|
|
},
|
|
});
|
|
|
|
if (user?.is_active) {
|
|
req.user = user;
|
|
}
|
|
}
|
|
next();
|
|
} catch {
|
|
// Continue without authentication for optional auth
|
|
next();
|
|
}
|
|
};
|
|
|
|
// Middleware to check if TFA is required for sensitive operations
|
|
const requireTfaIfEnabled = async (req, res, next) => {
|
|
try {
|
|
// Check if user has TFA enabled
|
|
const user = await prisma.users.findUnique({
|
|
where: { id: req.user.id },
|
|
select: { tfa_enabled: true },
|
|
});
|
|
|
|
// If TFA is enabled and not bypassed, require TFA verification
|
|
if (user?.tfa_enabled && !req.tfa_bypassed) {
|
|
return res.status(403).json({
|
|
error: "Two-factor authentication required for this operation",
|
|
requires_tfa: true,
|
|
});
|
|
}
|
|
|
|
next();
|
|
} catch (error) {
|
|
console.error("TFA requirement check error:", error);
|
|
return res.status(500).json({ error: "Authentication check failed" });
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
authenticateToken,
|
|
requireAdmin,
|
|
optionalAuth,
|
|
requireTfaIfEnabled,
|
|
};
|