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); } }; };