UNPKG

@frangoteam/fuxa

Version:

Web-based Process Visualization (SCADA/HMI/Dashboard) software

174 lines (154 loc) 4.75 kB
'use strict'; const jwt = require('jsonwebtoken'); const utils = require('../runtime/utils'); var secureEnabled = false; // Runtime fallback secret used only when no persistent secret is configured. var secretCode = utils.generateSecretCode(); var tokenExpiresIn = 60 * 60; // 60 minutes const adminGroups = [-1, 255]; function init(_secureEnabled, _secretCode, _tokenExpires) { secureEnabled = _secureEnabled; if (_secretCode) { secretCode = _secretCode; } if (_tokenExpires) { tokenExpiresIn = _tokenExpires; } } /** * Verify token * @param {*} token */ function verify (token) { return new Promise ((resolve, reject) => { jwt.verify(token, secretCode, (err, decoded) => { if (err) { console.error(`verify token error: ${err}`); reject(false); } else { resolve(true); } }); }); } /** * Verify WebAPI token (take from header) * @param {*} req * @param {*} res * @param {*} next */ function verifyToken (req, res, next) { let token = req.headers['x-access-token']; if (!token) { token = getGuestToken(); } if (token) { jwt.verify(token, secretCode, (err, decoded) => { if (err) { req.userId = "guest"; req.userGroups = ["guest"]; req.isAuthenticated = false; return next(); } req.userId = decoded.id; req.userGroups = decoded.groups; req.isAuthenticated = true; return next(); }); } else { // notice that no token was provided...} req.userId = null; req.userGroups = null; return next(); } } function requireAuth (req, res, next) { // Allow requests from FUXA interface (iframe embedding) // Check for common FUXA referer patterns const referer = req.headers.referer; if (referer) { // Allow if referer is from the same host (to support IP access without specific paths) const requestHost = req.headers.host; if (referer.startsWith(`http://${requestHost}`) || referer.startsWith(`https://${requestHost}`)) { return next(); } // Allow if referer contains common FUXA paths or is from the same server const fuxaPatterns = [ '/fuxa', '/editor', '/viewer', '/lab', '/home', 'localhost:', '127.0.0.1:', '0.0.0.0:' ]; const hasFuxaReferer = fuxaPatterns.some(pattern => referer.includes(pattern)); if (hasFuxaReferer) { return next(); } } // For direct access, require authentication let token = req.headers['x-access-token']; if (!token) { return res.status(401).json({ error: "unauthorized_error", message: "Authentication required!" }); } jwt.verify(token, secretCode, (err, decoded) => { if (err) { return res.status(401).json({ error: "unauthorized_error", message: "Invalid token!" }); } else { req.userId = decoded.id; req.userGroups = decoded.groups; next(); } }); } function getNewTokenFromRequest(req) { if (!req.isAuthenticated) { return null; } return jwt.sign({ id: req.userId, groups: req.userGroups }, secretCode, { expiresIn: tokenExpiresIn }); } function getGuestToken() { const token = jwt.sign({ id: "guest", groups: ["guest"] }, secretCode, { expiresIn: tokenExpiresIn }); return token; } function isGuestUser(userId, userGroups) { if (userId === 'guest') { return true; } if (Array.isArray(userGroups) && userGroups.includes('guest')) { return true; } return false; } function haveAdminPermission(permission) { if (permission === null || permission === undefined) { return false; } if (adminGroups.indexOf(permission) !== -1) { return true; } return false; } function getTokenExpiresIn() { return tokenExpiresIn; } module.exports = { init: init, verify: verify, verifyToken: verifyToken, requireAuth: requireAuth, getNewTokenFromRequest: getNewTokenFromRequest, getGuestToken: getGuestToken, get secretCode() { return secretCode }, get tokenExpiresIn() { return tokenExpiresIn }, haveAdminPermission: haveAdminPermission, adminGroups: adminGroups, isGuestUser: isGuestUser };