import jwt from "jsonwebtoken"; import crypto from "node:crypto"; import User from "../models/User/model.js"; import Access from "../models/Access/model.js"; import dotenv from "dotenv"; dotenv.config(); const { ECT_KEY, ECT_IV, ECT_METHOD } = process.env; export const getAccessToken = (payload) => { return jwt.sign(payload, ECT_KEY, { algorithm: "HS256", expiresIn: "7m", }); }; export const getEncryptedPayload = (payload) => { const cipher = crypto.createCipheriv(ECT_METHOD, ECT_KEY, ECT_IV); let encrypted = cipher.update(JSON.stringify(payload), "utf8", "hex"); encrypted += cipher.final("hex"); const tag = cipher.getAuthTag().toString("hex"); return `${ECT_IV}:${tag}:${encrypted}`; }; export const getDecryptedPayload = (payload) => { const [ivHex, authTagHex, encryptedHex] = payload.split(":"); const iv = Buffer.from(ivHex, "hex"); const authTag = Buffer.from(authTagHex, "hex"); const decipher = crypto.createDecipheriv(ECT_METHOD, ECT_KEY, ECT_IV); decipher.setAuthTag(authTag); // Verify integrity let decrypted = decipher.update(encryptedHex, "hex", "utf8"); decrypted += decipher.final("utf8"); return JSON.parse(decrypted); }; export const getRefreshToken = () => { return crypto.randomBytes(32).toString("hex"); }; export const authorize = (requiredModule, requiredPermission) => { return async (req, res, next) => { try { const authHeader = req.headers.authorization; if (!authHeader) { throw { code: 401, message: "Bearer Token Missing" }; } const token = authHeader.replace("Bearer ", ""); const verifiedPayload = jwt.verify(token, process.env.ECT_KEY || ""); // 1. Check if User exists const userExists = await User.exists({ _id: verifiedPayload.id }); if (!userExists) { throw { code: 404, message: "User not found" }; } // 2. Fetch Access and Populate Role // Assuming Access model has a 'user' field and a 'role' field const access = await Access.findOne({ user: verifiedPayload.id, }).populate("role"); console.log("access", access?.role?.modules); if (!access || !access.role) { throw { code: 403, message: "No role assigned to this user" }; } // 3. Verify Permissions const hasPermission = access?.role?.modules?.some( (mod) => (mod.module === requiredModule && mod.permission === requiredPermission) || (requiredModule === "generic" && requiredPermission === "generic"), ); if (!hasPermission) { throw { code: 403, message: `Insufficient permissions for ${requiredModule} (${requiredPermission})`, }; } // Success res.locals.user = verifiedPayload; next(); } catch (error) { console.error("AUTH_ERROR", error); res.status(error.code || 401).json(error); } }; }; export const authorizeWithEncryptedKey = ( requiredModule, requiredPermission, ) => { return async (req, res, next) => { try { const { key } = req.query; if (!key) { throw { code: 401, message: "Encrypted Auth Key Missing" }; } const verifiedPayload = getDecryptedPayload(key); const userExists = await User.exists({ _id: verifiedPayload.id }); if (!userExists) { throw { code: 404, message: "User not found" }; } res.locals.user = verifiedPayload; next(); } catch (error) { console.error("AUTH_ERROR", error); res.status(error.code || 401).json(error); } }; };