mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
Add permissions
This commit is contained in:
parent
cfee8a213a
commit
0a82574eb4
13 changed files with 135 additions and 27 deletions
27
server/config/roles.json
Normal file
27
server/config/roles.json
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"name": "admin",
|
||||||
|
"permissions": [
|
||||||
|
"crud_quiz",
|
||||||
|
"crud_folders",
|
||||||
|
"crud_images",
|
||||||
|
"crud_user"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "teacher",
|
||||||
|
"permissions": [
|
||||||
|
"crud_quiz",
|
||||||
|
"crud_folders",
|
||||||
|
"crud_images"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "student",
|
||||||
|
"permissions": [
|
||||||
|
"participate_quiz"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,11 @@ exports.UNAUTHORIZED_INVALID_TOKEN = {
|
||||||
code: 401
|
code: 401
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.UNAUTHORIZED_PERMISSION_MISSING = {
|
||||||
|
message: 'Accès refusé. Vous n\'avez pas les permissions nécessaires.',
|
||||||
|
code: 403
|
||||||
|
}
|
||||||
|
|
||||||
exports.MISSING_REQUIRED_PARAMETER = {
|
exports.MISSING_REQUIRED_PARAMETER = {
|
||||||
message: 'Paramètre requis manquant.',
|
message: 'Paramètre requis manquant.',
|
||||||
code: 400
|
code: 400
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ class UsersController {
|
||||||
|
|
||||||
async register(req, res, next) {
|
async register(req, res, next) {
|
||||||
try {
|
try {
|
||||||
const { email, password } = req.body;
|
const { email, password, role } = req.body;
|
||||||
|
|
||||||
if (!email || !password) {
|
if (!email || !password) {
|
||||||
throw new AppError(MISSING_REQUIRED_PARAMETER);
|
throw new AppError(MISSING_REQUIRED_PARAMETER);
|
||||||
}
|
}
|
||||||
|
|
||||||
await model.register(email, password);
|
await model.register(email, password, role);
|
||||||
|
|
||||||
emailer.registerConfirmation(email)
|
emailer.registerConfirmation(email)
|
||||||
|
|
||||||
|
|
@ -43,11 +43,12 @@ class UsersController {
|
||||||
throw new AppError(LOGIN_CREDENTIALS_ERROR);
|
throw new AppError(LOGIN_CREDENTIALS_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = jwt.create(user.email, user._id);
|
const token = jwt.create(user.email, user._id, user.role);
|
||||||
|
|
||||||
return res.status(200).json({
|
return res.status(200).json({
|
||||||
token: token,
|
token: token,
|
||||||
id: user.email
|
id: user.email,
|
||||||
|
role: user.role
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ dotenv.config();
|
||||||
|
|
||||||
class Token {
|
class Token {
|
||||||
|
|
||||||
create(email, userId) {
|
create(email, userId, role) {
|
||||||
return jwt.sign({ email, userId }, process.env.JWT_SECRET);
|
return jwt.sign({ email, userId, role }, process.env.JWT_SECRET);
|
||||||
}
|
}
|
||||||
|
|
||||||
authenticate(req, res, next) {
|
authenticate(req, res, next) {
|
||||||
|
|
|
||||||
23
server/middleware/rbac.js
Normal file
23
server/middleware/rbac.js
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
const Permissions = require('../models/permissions');
|
||||||
|
const AppError = require("./AppError");
|
||||||
|
const { UNAUTHORIZED_PERMISSION_MISSING} = require("../constants/errorCodes");
|
||||||
|
const jwt = require("jsonwebtoken");
|
||||||
|
|
||||||
|
class Rbac {
|
||||||
|
checkPermission = (...permissions) => {
|
||||||
|
return (req, res, next) => {
|
||||||
|
const userRole = req.user ? req.user.role : 'anonymous';
|
||||||
|
const userPermissions = Permissions.getPermissionsByRoleName(userRole);
|
||||||
|
|
||||||
|
for (let permission of permissions) {
|
||||||
|
if (!userPermissions.includes(permission)) {
|
||||||
|
return next(new AppError(UNAUTHORIZED_PERMISSION_MISSING));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return next();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Rbac;
|
||||||
13
server/models/permissions.js
Normal file
13
server/models/permissions.js
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
const Role = require('../models/role');
|
||||||
|
|
||||||
|
class Permissions {
|
||||||
|
constructor() {
|
||||||
|
this.permissions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getPermissionsByRoleName(roleName) {
|
||||||
|
const role = Role.getRoleByName(roleName);
|
||||||
|
return role ? role.permissions : [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = new Permissions;
|
||||||
30
server/models/role.js
Normal file
30
server/models/role.js
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
const roles = require('../config/roles.json');
|
||||||
|
|
||||||
|
class Role {
|
||||||
|
constructor() {
|
||||||
|
this.roles = roles.roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoleByName(name) {
|
||||||
|
return this.convertCrud(this.roles.find((role) => role.name === name));
|
||||||
|
}
|
||||||
|
|
||||||
|
getRoles() {
|
||||||
|
return this.roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
convertCrud(role) {
|
||||||
|
for (let permission of role.permissions) {
|
||||||
|
if (permission.startsWith("crud")) {
|
||||||
|
let resourceName = permission.split("_");
|
||||||
|
role.permissions.push("create_" + resourceName[1]);
|
||||||
|
role.permissions.push("read_" + resourceName[1]);
|
||||||
|
role.permissions.push("update_" + resourceName[1]);
|
||||||
|
role.permissions.push("delete_" + resourceName[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = new Role;
|
||||||
|
|
@ -19,7 +19,7 @@ class Users {
|
||||||
return await bcrypt.compare(password, hash)
|
return await bcrypt.compare(password, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
async register(email, password) {
|
async register(email, password, role) {
|
||||||
await db.connect()
|
await db.connect()
|
||||||
const conn = db.getConnection();
|
const conn = db.getConnection();
|
||||||
|
|
||||||
|
|
@ -34,6 +34,7 @@ class Users {
|
||||||
const newUser = {
|
const newUser = {
|
||||||
email: email,
|
email: email,
|
||||||
password: await this.hashPassword(password),
|
password: await this.hashPassword(password),
|
||||||
|
role: role,
|
||||||
created_at: new Date()
|
created_at: new Date()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,16 @@ const router = express.Router();
|
||||||
const jwt = require('../middleware/jwtToken.js');
|
const jwt = require('../middleware/jwtToken.js');
|
||||||
|
|
||||||
const foldersController = require('../controllers/folders.js')
|
const foldersController = require('../controllers/folders.js')
|
||||||
|
const rbac = require("../middleware/rbac");
|
||||||
|
|
||||||
router.post("/create", jwt.authenticate, foldersController.create);
|
router.post("/create", jwt.authenticate, rbac.checkPermission('create_folders'), foldersController.create);
|
||||||
router.get("/getUserFolders", jwt.authenticate, foldersController.getUserFolders);
|
router.get("/getUserFolders", jwt.authenticate, rbac.checkPermission('read_folders'), foldersController.getUserFolders);
|
||||||
router.get("/getFolderContent/:folderId", jwt.authenticate, foldersController.getFolderContent);
|
router.get("/getFolderContent/:folderId", jwt.authenticate, rbac.checkPermission('read_folders'), foldersController.getFolderContent);
|
||||||
router.delete("/delete/:folderId", jwt.authenticate, foldersController.delete);
|
router.delete("/delete/:folderId", jwt.authenticate, rbac.checkPermission('delete_folders'), foldersController.delete);
|
||||||
router.put("/rename", jwt.authenticate, foldersController.rename);
|
router.put("/rename", jwt.authenticate, rbac.checkPermission('update_folders'), foldersController.rename);
|
||||||
|
|
||||||
//router.post("/duplicate", jwt.authenticate, foldersController.duplicate);
|
router.post("/duplicate", jwt.authenticate, rbac.checkPermission('create_folders', 'read_folders'), foldersController.duplicate);
|
||||||
router.post("/duplicate", jwt.authenticate, foldersController.duplicate);
|
|
||||||
|
|
||||||
router.post("/copy/:folderId", jwt.authenticate, foldersController.copy);
|
router.post("/copy/:folderId", jwt.authenticate, rbac.checkPermission('create_folders', 'read_folders'), foldersController.copy);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
@ -6,10 +6,11 @@ const imagesController = require('../controllers/images.js')
|
||||||
|
|
||||||
// For getting the image out of the form data
|
// For getting the image out of the form data
|
||||||
const multer = require('multer');
|
const multer = require('multer');
|
||||||
|
const rbac = require("../middleware/rbac");
|
||||||
const storage = multer.memoryStorage();
|
const storage = multer.memoryStorage();
|
||||||
const upload = multer({ storage: storage });
|
const upload = multer({ storage: storage });
|
||||||
|
|
||||||
router.post("/upload", jwt.authenticate, upload.single('image'), imagesController.upload);
|
router.post("/upload", jwt.authenticate, rbac.checkPermission('create_images'), upload.single('image'), imagesController.upload);
|
||||||
router.get("/get/:id", imagesController.get);
|
router.get("/get/:id", imagesController.get);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
@ -3,17 +3,18 @@ const router = express.Router();
|
||||||
|
|
||||||
const jwt = require('../middleware/jwtToken.js');
|
const jwt = require('../middleware/jwtToken.js');
|
||||||
const quizController = require('../controllers/quiz.js')
|
const quizController = require('../controllers/quiz.js')
|
||||||
|
const rbac = require('../middleware/rbac.js');
|
||||||
|
|
||||||
router.post("/create", jwt.authenticate, quizController.create);
|
router.post("/create", jwt.authenticate, rbac.checkPermission('create_quiz'), quizController.create);
|
||||||
router.get("/get/:quizId", jwt.authenticate, quizController.get);
|
router.get("/get/:quizId", jwt.authenticate, rbac.checkPermission('participate_quiz'), quizController.get);
|
||||||
router.delete("/delete/:quizId", jwt.authenticate, quizController.delete);
|
router.delete("/delete/:quizId", jwt.authenticate, rbac.checkPermission('delete_quiz'), quizController.delete);
|
||||||
router.put("/update", jwt.authenticate, quizController.update);
|
router.put("/update", jwt.authenticate, rbac.checkPermission('update_quiz'), quizController.update);
|
||||||
router.put("/move", jwt.authenticate, quizController.move);
|
router.put("/move", jwt.authenticate, rbac.checkPermission('update_quiz'), quizController.move);
|
||||||
|
|
||||||
router.post("/duplicate", jwt.authenticate, quizController.duplicate);
|
router.post("/duplicate", jwt.authenticate, rbac.checkPermission('create_quiz', 'read_quiz'), quizController.duplicate);
|
||||||
router.post("/copy/:quizId", jwt.authenticate, quizController.copy);
|
router.post("/copy/:quizId", jwt.authenticate, rbac.checkPermission('create_quiz', 'read_quiz'), quizController.copy);
|
||||||
router.put("/Share", jwt.authenticate, quizController.Share);
|
router.put("/Share", jwt.authenticate, rbac.checkPermission('create_quiz', 'read_quiz'), quizController.Share);
|
||||||
router.get("/getShare/:quizId", jwt.authenticate, quizController.getShare);
|
router.get("/getShare/:quizId", jwt.authenticate, rbac.checkPermission('create_quiz', 'read_quiz'), quizController.getShare);
|
||||||
router.post("/receiveShare", jwt.authenticate, quizController.receiveShare);
|
router.post("/receiveShare", jwt.authenticate, rbac.checkPermission('create_quiz', 'read_quiz'), quizController.receiveShare);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
@ -3,11 +3,12 @@ const router = express.Router();
|
||||||
|
|
||||||
const jwt = require('../middleware/jwtToken.js');
|
const jwt = require('../middleware/jwtToken.js');
|
||||||
const usersController = require('../controllers/users.js')
|
const usersController = require('../controllers/users.js')
|
||||||
|
const rbac = require("../middleware/rbac");
|
||||||
|
|
||||||
router.post("/register", usersController.register);
|
router.post("/register", usersController.register);
|
||||||
router.post("/login", usersController.login);
|
router.post("/login", usersController.login);
|
||||||
router.post("/reset-password", usersController.resetPassword);
|
router.post("/reset-password", usersController.resetPassword);
|
||||||
router.post("/change-password", jwt.authenticate, usersController.changePassword);
|
router.post("/change-password", jwt.authenticate, usersController.changePassword);
|
||||||
router.post("/delete-user", jwt.authenticate, usersController.delete);
|
router.post("/delete-user", jwt.authenticate, rbac.checkPermission('delete_user'), usersController.delete);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
@ -5,6 +5,7 @@ const setupWebsocket = (io) => {
|
||||||
let totalConnections = 0;
|
let totalConnections = 0;
|
||||||
|
|
||||||
io.on("connection", (socket) => {
|
io.on("connection", (socket) => {
|
||||||
|
// Get jwt and roles
|
||||||
if (totalConnections >= MAX_TOTAL_CONNECTIONS) {
|
if (totalConnections >= MAX_TOTAL_CONNECTIONS) {
|
||||||
console.log("Connection limit reached. Disconnecting client.");
|
console.log("Connection limit reached. Disconnecting client.");
|
||||||
socket.emit(
|
socket.emit(
|
||||||
|
|
@ -24,6 +25,10 @@ const setupWebsocket = (io) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
socket.on("create-room", (sentRoomName) => {
|
socket.on("create-room", (sentRoomName) => {
|
||||||
|
// If roles authorize else send error message
|
||||||
|
// else {
|
||||||
|
// socket.emit('access_denied', 'You do not have permission to perform this action');
|
||||||
|
// }
|
||||||
if (sentRoomName) {
|
if (sentRoomName) {
|
||||||
const roomName = sentRoomName.toUpperCase();
|
const roomName = sentRoomName.toUpperCase();
|
||||||
if (!io.sockets.adapter.rooms.get(roomName)) {
|
if (!io.sockets.adapter.rooms.get(roomName)) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue