From fdaabe5189405a14d05ca1d13a612fc52bebf1c9 Mon Sep 17 00:00:00 2001 From: shubham <49603826+shubhdevelop@users.noreply.github.com> Date: Fri, 30 Aug 2024 14:24:18 +0530 Subject: [PATCH] [feat]Super User Privilege Toggle --- controllers/users.js | 53 ++++++++++ middlewares/authenticate.js | 21 +++- routes/users.js | 2 + test/integration/users.test.js | 174 +++++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+), 5 deletions(-) diff --git a/controllers/users.js b/controllers/users.js index 858212fa4..125212603 100644 --- a/controllers/users.js +++ b/controllers/users.js @@ -30,6 +30,7 @@ const { addLog } = require("../models/logs"); const { getUserStatus } = require("../models/userStatus"); const config = require("config"); const discordDeveloperRoleId = config.get("discordDeveloperRoleId"); +const authService = require("../services/authService"); const verifyUser = async (req, res) => { const userId = req.userData.id; @@ -376,6 +377,9 @@ const getSelfDetails = async (req, res) => { const user = await dataAccess.retrieveUsers({ userdata: req.userData, }); + if (req.userData.superUserAccess === false) { + user.roles.super_user = false; + } return res.send(user); } return res.boom.notFound("User doesn't exist"); @@ -827,6 +831,53 @@ const setInDiscordScript = async (req, res) => { } }; +const getSuperUserAccessStatus = async (req, res) => { + try { + if (req.userData.superUserAccess !== undefined) { + return res.json({ currentAccess: req.userData.superUserAccess }); + } else { + return res.json({ message: "Super User Access Modifier Not Set!" }); + } + } catch (error) { + return res.boom.badImplementation({ message: INTERNAL_SERVER_ERROR }); + } +}; + +const setSuperUserAccessLimiter = async (req, res) => { + try { + let value; + switch (req.query.value) { + case "true": + value = true; + break; + case "false": + value = false; + break; + default: + break; + } + if (value !== undefined) { + const token = req.cookies[config.get("userToken.cookieName")]; + const { userId } = authService.decodeAuthToken(token); + const newToken = authService.generateAuthToken({ userId, superUserAccess: value }); + const rdsUiUrl = new URL(config.get("services.rdsUi.baseUrl")); + res.cookie(config.get("userToken.cookieName"), newToken, { + domain: rdsUiUrl.hostname, + expires: new Date(Date.now() + config.get("userToken.ttl") * 1000), + httpOnly: true, + secure: true, + sameSite: "lax", + }); + return res.json({ message: "Super User Privilege Access Set!", currentAccess: value }); + } else { + return res.boom.badRequest("Wrong value in query param, value can be either true or false"); + } + } catch (error) { + logger.error(`Error while Setting Super Privilege Access Limiter: ${error}`); + return res.boom.badImplementation({ message: INTERNAL_SERVER_ERROR }); + } +}; + const updateRoles = async (req, res) => { try { const result = await dataAccess.retrieveUsers({ id: req.params.id }); @@ -985,5 +1036,7 @@ module.exports = { archiveUserIfNotInDiscord, usersPatchHandler, isDeveloper, + setSuperUserAccessLimiter, + getSuperUserAccessStatus, getIdentityStats, }; diff --git a/middlewares/authenticate.js b/middlewares/authenticate.js index 667d41b32..16bf1c776 100644 --- a/middlewares/authenticate.js +++ b/middlewares/authenticate.js @@ -42,7 +42,6 @@ const checkRestricted = async (req, res, next) => { module.exports = async (req, res, next) => { try { let token = req.cookies[config.get("userToken.cookieName")]; - /** * Enable Bearer Token authentication for NON-PRODUCTION environments * This is enabled as Swagger UI does not support cookie authe @@ -51,12 +50,24 @@ module.exports = async (req, res, next) => { token = req.headers.authorization.split(" ")[1]; } - const { userId } = authService.verifyAuthToken(token); + const { userId, superUserAccess } = authService.verifyAuthToken(token); + const userDoc = await dataAccess.retrieveUsers({ id: userId }); + let userData; // add user data to `req.userData` for further use - const userData = await dataAccess.retrieveUsers({ id: userId }); - req.userData = userData.user; - + if (superUserAccess === false) { + userData = userDoc.user; + userData.roles.super_user = false; + userData.superUserAccess = false; + } else if (superUserAccess === true || superUserAccess === undefined) { + userData = userDoc.user; + if (superUserAccess === true) { + userData.superUserAccess = true; + } else { + userData.superUserAccess = undefined; + } + } + req.userData = userData; return checkRestricted(req, res, next); } catch (err) { logger.error(err); diff --git a/routes/users.js b/routes/users.js index 9b29099d7..daf37004f 100644 --- a/routes/users.js +++ b/routes/users.js @@ -19,6 +19,8 @@ router.get("/userId/:userId", users.getUserById); router.patch("/self", authenticate, userValidator.updateUser, users.updateSelf); router.get("/", userValidator.getUsers, users.getUsers); router.get("/self", authenticate, users.getSelfDetails); +router.get("/set-super-user-access", authenticate, users.setSuperUserAccessLimiter); +router.get("/get-super-user-access-status", authenticate, users.getSuperUserAccessStatus); router.get("/isDeveloper", authenticate, users.isDeveloper); router.get("/isUsernameAvailable/:username", authenticate, users.getUsernameAvailabilty); router.get("/username", authenticate, userValidator.validateGenerateUsernameQuery, users.generateUsername); diff --git a/test/integration/users.test.js b/test/integration/users.test.js index 0e063fab0..2ee95c2e4 100644 --- a/test/integration/users.test.js +++ b/test/integration/users.test.js @@ -924,6 +924,42 @@ describe("Users", function () { }); }); + it("Should return the logged in super_user with modified privilege, super_user : false, based on superUserAccess in jwt token", async function () { + const superUser = userData[4]; + const userId = await addUser(superUser); + jwt = authService.generateAuthToken({ userId, superUserAccess: false }); + const res = await chai.request(app).get("/users/self").set("cookie", `${cookieName}=${jwt}`); + + expect(res).to.have.status(200); + expect(res.body).to.be.a("object"); + expect(res.body.roles.super_user).to.be.equal(false); + await cleanDb(); + }); + + it("Should return the logged in super_user with unmodified privileges, super_user : true, based on superUserAccess in jwt token", async function () { + const superUser = userData[4]; + const userId = await addUser(superUser); + jwt = authService.generateAuthToken({ userId, superUserAccess: true }); + const res = await chai.request(app).get("/users/self").set("cookie", `${cookieName}=${jwt}`); + + expect(res).to.have.status(200); + expect(res.body).to.be.a("object"); + expect(res.body.roles.super_user).to.be.equal(true); + await cleanDb(); + }); + + it("Should return the logged in super_user as it is if the superUserAccess not found in jwt token", async function () { + const superUser = userData[4]; + const userId = await addUser(superUser); + jwt = authService.generateAuthToken({ userId }); + const res = await chai.request(app).get("/users/self").set("cookie", `${cookieName}=${jwt}`); + + expect(res).to.have.status(200); + expect(res.body).to.be.a("object"); + expect(res.body.roles.super_user).to.be.equal(true); + await cleanDb(); + }); + it("Should return 401 if not logged in", function (done) { chai .request(app) @@ -2419,4 +2455,142 @@ describe("Users", function () { }); }); }); + + describe("GET /get-super-user-access-status", function () { + beforeEach(async function () { + userId = await addUser(); + }); + + afterEach(async function () { + await cleanDb(); + }); + + it("Should return true if the token has superUserAccess role in it, and it's set to be true", function (done) { + jwt = authService.generateAuthToken({ userId, superUserAccess: true }); + chai + .request(app) + .get("/users/get-super-user-access-status") + .set("cookie", `${cookieName}=${jwt}`) + .end((err, res) => { + if (err) { + return done(err); + } + expect(res).to.have.status(200); + expect(res.body).to.be.a("object"); + expect(res.body).to.have.a.property("currentAccess"); + expect(res.body.currentAccess).to.be.equal(true); + return done(); + }); + }); + + it("Should return false if the token has superUserAccess role in it, and it's set to be false", function (done) { + jwt = authService.generateAuthToken({ userId, superUserAccess: false }); + chai + .request(app) + .get("/users/get-super-user-access-status") + .set("cookie", `${cookieName}=${jwt}`) + .end((err, res) => { + if (err) { + return done(err); + } + + expect(res).to.have.status(200); + expect(res.body).to.be.a("object"); + expect(res.body).to.have.property("currentAccess"); + expect(res.body.currentAccess).to.be.equal(false); + return done(); + }); + }); + + it("Should return a message: 'Super User Access Modifier Not Set!', if superUserAccess not set in jwt token", function (done) { + jwt = authService.generateAuthToken({ userId }); + chai + .request(app) + .get("/users/get-super-user-access-status") + .set("cookie", `${cookieName}=${jwt}`) + .end((err, res) => { + if (err) { + return done(err); + } + + expect(res).to.have.status(200); + expect(res.body).to.be.a("object"); + expect(res.body).to.not.have.property("currentAccess"); + expect(res.body).to.have.property("message"); + expect(res.body.currentAccess).to.be.equal(undefined); + expect(res.body.message).to.be.equal("Super User Access Modifier Not Set!"); + return done(); + }); + }); + }); + + describe("GET /set-super-user-access", function () { + beforeEach(async function () { + userId = await addUser(); + }); + + afterEach(async function () { + await cleanDb(); + }); + + it("Should return currentAccess: true, with message: 'Super User Privilege Access Set!'", function (done) { + jwt = authService.generateAuthToken({ userId }); + chai + .request(app) + .get("/users/set-super-user-access?value=true") + .set("cookie", `${cookieName}=${jwt}`) + .end((err, res) => { + if (err) { + return done(err); + } + expect(res).to.have.status(200); + expect(res.body).to.be.a("object"); + expect(res.body).to.have.a.property("currentAccess"); + expect(res.body).to.have.a.property("message"); + expect(res.body.currentAccess).to.be.equal(true); + expect(res.body.message).to.be.equal("Super User Privilege Access Set!"); + return done(); + }); + }); + + it("Should return currentAccess: false, with message: 'Super User Privilege Access Set!'", function (done) { + jwt = authService.generateAuthToken({ userId }); + chai + .request(app) + .get("/users/set-super-user-access?value=false") + .set("cookie", `${cookieName}=${jwt}`) + .end((err, res) => { + if (err) { + return done(err); + } + expect(res).to.have.status(200); + expect(res.body).to.be.a("object"); + expect(res.body).to.have.a.property("currentAccess"); + expect(res.body).to.have.a.property("message"); + expect(res.body.currentAccess).to.be.equal(false); + expect(res.body.message).to.be.equal("Super User Privilege Access Set!"); + return done(); + }); + }); + + it("Should return status 400", function (done) { + jwt = authService.generateAuthToken({ userId }); + chai + .request(app) + .get("/users/set-super-user-access?value=xyz") + .set("cookie", `${cookieName}=${jwt}`) + .end((err, res) => { + if (err) { + return done(err); + } + expect(res).to.have.status(400); + expect(res.body).to.be.a("object"); + expect(res.body).to.not.have.a.property("currentAccess"); + expect(res.body).to.have.a.property("message"); + expect(res.body.currentAccess).to.be.equal(undefined); + expect(res.body.message).to.be.equal("Wrong value in query param, value can be either true or false"); + return done(); + }); + }); + }); });