From 180c6d7e832c3f0ae32615e977a35630351cdeba Mon Sep 17 00:00:00 2001 From: Entwicklung Date: Mon, 5 Sep 2022 21:19:36 +0200 Subject: [PATCH] refactor all JWT verification of isModerator and get BoardRole --- server/jwtBoardnameAuth.js | 107 ++++++++++++++++++++----------------- server/jwtauth.js | 27 ++-------- server/server.js | 8 +-- 3 files changed, 67 insertions(+), 75 deletions(-) diff --git a/server/jwtBoardnameAuth.js b/server/jwtBoardnameAuth.js index 2991af5..e68c94c 100644 --- a/server/jwtBoardnameAuth.js +++ b/server/jwtBoardnameAuth.js @@ -28,56 +28,18 @@ config = require("./configuration.js"), jsonwebtoken = require("jsonwebtoken"); /** - * Validates jwt and returns whether board name fits to the board name given in the JWT - * @param {URL} url - * @param {string} boardNameIn - * @returns {boolean} - True if user is a moderator, else false - * @throws {Error} - If no token is provided when it should be or when the board name is incorrect - */ -function checkBoardName(url, boardNameIn) { - var roomIsCorrect = true; - if (config.AUTH_SECRET_KEY != "") { - var token = url.searchParams.get("token"); - if (token) { - roomIsCorrect = getBoardnamefromToken(token, boardNameIn); - } else { - throw new Error("No token provided"); - } - } - return roomIsCorrect; -} - -/** - * Check if user is a moderator - * @param {string} token + * This function checks if a board name is set in the roles claim. + * Returns true of the board name is set in the JWT and the board name matches the board name in the URL + * @param {string} url * @param {string} boardNameIn + @returns {boolean} - True if user does not have the role forbidden false if the user hase the role forbidden + @throws {Error} - If no boardname match */ -function getBoardnamefromToken(token, boardNameIn) { - if (config.AUTH_SECRET_KEY != "") { - var payload = jsonwebtoken.verify(token, config.AUTH_SECRET_KEY); - var roles = payload.roles; - var oneHasBoardName = false; - var oneHasCorretBoardname = false; - if (roles) { - for (var line of roles) { - var role = parse_role(line); - if (role.board_name !== '') { - oneHasBoardName = true; - } - if (role.board_name === boardNameIn) { - return true; - } - } - if (!oneHasBoardName) { - return true; - } - - throw new Error("No board name match"); - - } else { - return true; - } +function checkBoardnameInToken(url, boardNameIn) { + var token = url.searchParams.get("token"); + if (roleInBoard(token, boardNameIn) === 'forbidden') { + throw new Error("Acess Forbidden"); } } @@ -85,4 +47,53 @@ function parse_role(role) { let [_, role_name, board_name] = role.match(/^([^:]*):?(.*)$/); return {role_name, board_name} } -module.exports = {checkBoardName, parse_role}; + +/** + * This function checks if a oard name is set in the roles claim. + * Returns string depending on the role in the board + * @param {string} token + * @param {string} board + @returns {string} "moderator"|"editor"|"forbidden" + */ +function roleInBoard(token, board = null) { + if (config.AUTH_SECRET_KEY != "") { + if (!token) { + throw new Error("No token provided"); + } + var payload = jsonwebtoken.verify(token, config.AUTH_SECRET_KEY); + + var roles = payload.roles; + var oneHasBoardName = false; + var oneHasModerator = false; + + if (roles) { + for (var line of roles) { + var role = parse_role(line); + + if (role.board_name !== '') { + oneHasBoardName = true; + } + if (role.role_name === "moderator") { + oneHasModerator = true; + } + if (role.board_name === board) { + return role.role_name; + } + } + if ((!board && oneHasModerator) || !oneHasBoardName) { + if (oneHasModerator) { + return "moderator"; + } else { + return "editor"; + } + } + return "forbidden"; + } else { + return "editor"; + } + } else { + return "editor"; + } +} + +module.exports = {checkBoardnameInToken, roleInBoard}; diff --git a/server/jwtauth.js b/server/jwtauth.js index ddd5bfd..4678b76 100644 --- a/server/jwtauth.js +++ b/server/jwtauth.js @@ -24,9 +24,10 @@ * @licend */ + config = require("./configuration.js"), jsonwebtoken = require("jsonwebtoken"); - +const {roleInBoard} = require("./jwtBoardnameAuth"); /** * Validates jwt and returns whether user is a moderator * @param {URL} url @@ -38,7 +39,7 @@ function checkUserPermission(url) { if (config.AUTH_SECRET_KEY != "") { var token = url.searchParams.get("token"); if (token) { - isModerator = checkIfModerator(token); + isModerator = roleInBoard(token) === "moderator"; } else { // Error out as no token provided throw new Error("No token provided"); @@ -47,25 +48,5 @@ function checkUserPermission(url) { return isModerator; } -/** - * Check if user is a moderator - * @param {string} token - */ - function checkIfModerator(token) { - if(config.AUTH_SECRET_KEY != "") { - var payload = jsonwebtoken.verify(token, config.AUTH_SECRET_KEY); - var roles = payload.roles; - if(roles) { - for (var role of roles) { - if (role.match(/^moderator/gm)) { - return true; - } - return false; - } - } else { - return false; - } - } - } -module.exports = { checkUserPermission, checkIfModerator }; +module.exports = { checkUserPermission }; diff --git a/server/server.js b/server/server.js index 68d346f..4e7ea71 100644 --- a/server/server.js +++ b/server/server.js @@ -121,13 +121,13 @@ function handleRequest(request, response) { if (parts.length === 1) { // '/boards?board=...' This allows html forms to point to boards var boardName = parsedUrl.searchParams.get("board") || "anonymous"; - jwtBoardName.checkBoardName(parsedUrl, boardName); + jwtBoardName.checkBoardnameInToken(parsedUrl, boardName); var headers = { Location: "boards/" + encodeURIComponent(boardName) }; response.writeHead(301, headers); response.end(); } else if (parts.length === 2 && parsedUrl.pathname.indexOf(".") === -1) { var boardName = validateBoardName(parts[1]); - jwtBoardName.checkBoardName(parsedUrl, boardName); + jwtBoardName.checkBoardnameInToken(parsedUrl, boardName); boardTemplate.serve(request, response, isModerator); // If there is no dot and no directory, parts[1] is the board name } else { @@ -142,7 +142,7 @@ function handleRequest(request, response) { config.HISTORY_DIR, "board-" + boardName + ".json" ); - jwtBoardName.checkBoardName(parsedUrl, boardName); + jwtBoardName.checkBoardnameInToken(parsedUrl, boardName); if (parts.length > 2 && /^[0-9A-Za-z.\-]+$/.test(parts[2])) { history_file += "." + parts[2] + ".bak"; } @@ -165,7 +165,7 @@ function handleRequest(request, response) { config.HISTORY_DIR, "board-" + boardName + ".json" ); - jwtBoardName.checkBoardName(parsedUrl, boardName); + jwtBoardName.checkBoardnameInToken(parsedUrl, boardName); response.writeHead(200, { "Content-Type": "image/svg+xml", "Content-Security-Policy": CSP,