Skip to content

Commit

Permalink
Admin/User Role Based Access (#38)
Browse files Browse the repository at this point in the history
* added role model

* added middleware check for admin/user

* added auth middleware & updated roles

* updated email from header field

* updated checkRoles

* appened user info to headers for auth

* moved middleware to seperate directory

* fixed imports for checkrole

* fixed authentication middleware

* cleanup

* removed all check role stuff

* Update AuthenticationMiddleware.js

* added routes from main
  • Loading branch information
o-bm authored Mar 23, 2024
1 parent 8a09c14 commit c4a112d
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 7 deletions.
1 change: 1 addition & 0 deletions server/controllers/UserController.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ exports.delete = async (req, res) => {
await User.destroy({ where: { id } });
res.status(204).send();
};

33 changes: 31 additions & 2 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,34 @@ const express = require("express");
const path = require("node:path");
const db = require("./models");
const importChallenges = require("./scripts/importChallenges");
const { ErrorHandler } = require("./routes/ErrorHandlingMiddleware");
const loggingMiddleware = require("./routes/LoggingMiddleware");
const { ErrorHandler } = require("./middleware/ErrorHandlingMiddleware");
const loggingMiddleware = require("./middleware/LoggingMiddleware");
const authMiddleware = require('./middleware/AuthenticationMiddleware');

const app = express();

app.use(express.json());

const PORT = process.env.PORT || 8080;

// For testing purposes
// app.post('/test-auth', authMiddleware, (req, res) => {
// const user = req.user;

// const userInfo = {
// id: user.id,
// username: user.username,
// email: user.email,
// role: user.role,
// };

// res.json(userInfo);
// });


app.use(loggingMiddleware);
app.use(authMiddleware);

// Sync Sequelize models
db.sequelize.sync().then(async () => {
// Use { force: true } cautiously as it will drop existing tables
Expand Down Expand Up @@ -40,6 +59,15 @@ app.use("/api/comments", comments);

app.use(ErrorHandler);

//uncomment for production
// app.use(express.static(path.resolve(__dirname, "../client/dist")))

//Send all non-api requests to the React app.
//uncomment for production
// app.get("*", (req, res) => {
// res.sendFile(path.resolve(__dirname, "../client/dist", "index.html"))
// })

// ENV FILE SPECIFICATION
// PROD=prod|dev -> prod runs in production mode
//
Expand All @@ -51,3 +79,4 @@ if ("ENV" in process.env && process.env.ENV === "prod") {
res.sendFile(path.resolve(__dirname, "../client/dist", "index.html"));
});
}

26 changes: 26 additions & 0 deletions server/middleware/AuthenticationMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const db = require('../models');

async function authMiddleware(req, res, next) {
try {
const utorid = req.headers.utorid;
const http_mail = req.headers.http_mail;

let user = await db.User.findOne({ where: { username: utorid } });

if (!user) {
user = await db.User.create({
username: utorid,
email: http_mail,
role: 'user',
});
}

req.user = user;
next();
} catch (error) {
console.error('Error ensuring user exists:', error);
res.status(500).send({ error: 'Internal Server Error' });
}
}

module.exports = authMiddleware;
34 changes: 34 additions & 0 deletions server/middleware/ErrorHandlingMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
function ErrorHandler(err, req, res, next) {
console.error("Error", err);
let code = 500;
if (err instanceof HandledError) {
code = err.code;
}
res.status(code).json({
error: err.message,
});
}

function AsyncWrapController(controller) {
for (const key in controller) {
if (typeof controller[key] === "function") {
// console.log(`Changed ${key} to async.`);
controller[key] = AsyncDecorator(controller[key]);
}
}
}

function AsyncDecorator(fn) {
return (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch((e) => next(e));
};
}

class HandledError extends Error {
constructor(code, message) {
super(message);
this.code = code;
}
}

module.exports = { ErrorHandler, AsyncWrapController, HandledError };
6 changes: 6 additions & 0 deletions server/middleware/LoggingMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function LoggingMiddleware(req, res, next) {
console.log(`Requesting ${req.originalUrl} /w`, req.params, req.body);
next();
}

module.exports = LoggingMiddleware;
14 changes: 9 additions & 5 deletions server/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@ module.exports = (sequelize, DataTypes) => {
allowNull: false,
unique: true
},
passwordHash: {
type: DataTypes.STRING,
allowNull: false
},
preferredName: DataTypes.STRING,
// preferredName: DataTypes.STRING,
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
role: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 'user', // default role is 'user'
validate: {
isIn: [['user', 'admin']], // Ensures the role is either 'user' or 'admin'
}
},
score: DataTypes.INTEGER
});
User.associate = function(models) {
Expand Down

0 comments on commit c4a112d

Please sign in to comment.