diff --git a/backend/api/controllers/config.js b/backend/api/controllers/config.js index 5e72920dd..6f4114eaf 100644 --- a/backend/api/controllers/config.js +++ b/backend/api/controllers/config.js @@ -2,16 +2,18 @@ const ConfigDAO = require("../../dao/config"); const { validateConfig } = require("../../handlers/validation"); class ConfigController { - static async getConfig(req, res) { - const { uid } = req.decodedToken; - let config = await ConfigDAO.getConfig(uid); - return res.status(200).json(config); + static async getConfig(req, _res) { + const { uid } = req.ctx.decodedToken; + + return await ConfigDAO.getConfig(uid); } static async saveConfig(req, res) { const { config } = req.body; - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; + validateConfig(config); await ConfigDAO.saveConfig(uid, config); + return res.sendStatus(200); } } diff --git a/backend/api/controllers/leaderboards.js b/backend/api/controllers/leaderboards.js index 498b22121..7e565e769 100644 --- a/backend/api/controllers/leaderboards.js +++ b/backend/api/controllers/leaderboards.js @@ -1,49 +1,40 @@ +const _ = require("lodash"); const LeaderboardsDAO = require("../../dao/leaderboards"); const { verifyIdToken } = require("../../handlers/auth"); class LeaderboardsController { - static async get(req, res) { + static async get(req, _res) { const { language, mode, mode2, skip, limit } = req.query; + const { uid } = req.ctx.decodedToken; - let uid; + const leaderboard = await LeaderboardsDAO.get( + mode, + mode2, + language, + skip, + limit + ); - const { authorization } = req.headers; - if (authorization) { - const token = authorization.split(" "); - if (token[0].trim() == "Bearer") - req.decodedToken = await verifyIdToken(token[1]); - uid = req.decodedToken.uid; - } - - if (!language || !mode || !mode2 || !skip) { - return res.status(400).json({ - message: "Missing parameters", - }); - } - let retval = await LeaderboardsDAO.get(mode, mode2, language, skip, limit); - retval.forEach((item) => { - if (uid && item.uid == uid) { - // - } else { - delete item.discordId; - delete item.uid; - delete item.difficulty; - delete item.language; - } + const normalizedLeaderboard = _.map(leaderboard, (entry) => { + return uid && entry.uid === uid + ? entry + : _.omit(entry, ["discordId", "uid", "difficulty", "language"]); }); - return res.status(200).json(retval); + + return normalizedLeaderboard; } static async getRank(req, res) { const { language, mode, mode2 } = req.query; - const { uid } = req.decodedToken; - if (!language || !mode || !mode2 || !uid) { + const { uid } = req.ctx.decodedToken; + + if (!uid) { return res.status(400).json({ - message: "Missing parameters", + message: "Missing user id.", }); } - let retval = await LeaderboardsDAO.getRank(mode, mode2, language, uid); - return res.status(200).json(retval); + + return await LeaderboardsDAO.getRank(mode, mode2, language, uid); } } diff --git a/backend/api/controllers/new-quotes.js b/backend/api/controllers/new-quotes.js index 98a2ad38b..9892d75c4 100644 --- a/backend/api/controllers/new-quotes.js +++ b/backend/api/controllers/new-quotes.js @@ -6,7 +6,7 @@ const Captcha = require("../../handlers/captcha"); class NewQuotesController { static async getQuotes(req, _res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const userInfo = await UserDAO.getUser(uid); if (!userInfo.quoteMod) { throw new MonkeyError(403, "You don't have permission to do this"); @@ -15,7 +15,7 @@ class NewQuotesController { } static async addQuote(req, _res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { text, source, language, captcha } = req.body; if (!(await Captcha.verify(captcha))) { throw new MonkeyError(400, "Captcha check failed"); @@ -24,7 +24,7 @@ class NewQuotesController { } static async approve(req, _res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { quoteId, editText, editSource } = req.body; const userInfo = await UserDAO.getUser(uid); if (!userInfo.quoteMod) { @@ -37,7 +37,7 @@ class NewQuotesController { } static async refuse(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { quoteId } = req.body; await NewQuotesDAO.refuse(quoteId, uid); diff --git a/backend/api/controllers/preset.js b/backend/api/controllers/preset.js index 2d7d15c28..38912911b 100644 --- a/backend/api/controllers/preset.js +++ b/backend/api/controllers/preset.js @@ -7,35 +7,33 @@ const MonkeyError = require("../../handlers/error"); class PresetController { static async getPresets(req, res) { - const { uid } = req.decodedToken; - let presets = await PresetDAO.getPresets(uid); - return res.status(200).json(presets); + const { uid } = req.ctx.decodedToken; + + return await PresetDAO.getPresets(uid); } static async addPreset(req, res) { const { name, config } = req.body; - const { uid } = req.decodedToken; - if (!isTagPresetNameValid(name)) - throw new MonkeyError(400, "Invalid preset name."); - validateConfig(config); - let preset = await PresetDAO.addPreset(uid, name, config); - return res.status(200).json(preset); + const { uid } = req.ctx.decodedToken; + + return await PresetDAO.addPreset(uid, name, config); } static async editPreset(req, res) { const { _id, name, config } = req.body; - const { uid } = req.decodedToken; - if (!isTagPresetNameValid(name)) - throw new MonkeyError(400, "Invalid preset name."); - if (config) validateConfig(config); + const { uid } = req.ctx.decodedToken; + await PresetDAO.editPreset(uid, _id, name, config); + return res.sendStatus(200); } static async removePreset(req, res) { const { _id } = req.body; - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; + await PresetDAO.removePreset(uid, _id); + return res.sendStatus(200); } } diff --git a/backend/api/controllers/quote-ratings.js b/backend/api/controllers/quote-ratings.js index 15ba0b433..534ec84e5 100644 --- a/backend/api/controllers/quote-ratings.js +++ b/backend/api/controllers/quote-ratings.js @@ -9,7 +9,7 @@ class QuoteRatingsController { } static async submitRating(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; let { quoteId, rating, language } = req.body; quoteId = parseInt(quoteId); diff --git a/backend/api/controllers/quotes.js b/backend/api/controllers/quotes.js index fa5144dff..76cd20b7d 100644 --- a/backend/api/controllers/quotes.js +++ b/backend/api/controllers/quotes.js @@ -7,7 +7,7 @@ const Logger = require("../../handlers/logger"); class QuotesController { static async reportQuote(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const user = await UserDAO.getUser(uid); if (user.cannotReport) { diff --git a/backend/api/controllers/result.js b/backend/api/controllers/result.js index 853b5a699..2e3afa7ec 100644 --- a/backend/api/controllers/result.js +++ b/backend/api/controllers/result.js @@ -33,27 +33,27 @@ try { class ResultController { static async getResults(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const results = await ResultDAO.getResults(uid); return res.status(200).json(results); } static async deleteAll(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; await ResultDAO.deleteAll(uid); Logger.log("user_results_deleted", "", uid); return res.sendStatus(200); } static async updateTags(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { tags, resultid } = req.body; await ResultDAO.updateTags(uid, resultid, tags); return res.sendStatus(200); } static async addResult(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { result } = req.body; result.uid = uid; if (validateObjectValues(result) > 0) @@ -100,7 +100,7 @@ class ResultController { let resulthash = result.hash; delete result.hash; - if (req.context.configuration.resultObjectHashCheck.enabled) { + if (req.ctx.configuration.resultObjectHashCheck.enabled) { const serverhash = objecthash(result); if (serverhash !== resulthash) { Logger.log( diff --git a/backend/api/controllers/user.js b/backend/api/controllers/user.js index 20ec394f7..c58508909 100644 --- a/backend/api/controllers/user.js +++ b/backend/api/controllers/user.js @@ -16,14 +16,14 @@ const uaparser = require("ua-parser-js"); class UserController { static async createNewUser(req, res) { const { name } = req.body; - const { email, uid } = req.decodedToken; + const { email, uid } = req.ctx.decodedToken; await UsersDAO.addUser(name, email, uid); Logger.log("user_created", `${name} ${email}`, uid); return res.sendStatus(200); } static async deleteUser(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const userInfo = await UsersDAO.getUser(uid); await UsersDAO.deleteUser(uid); Logger.log("user_deleted", `${userInfo.email} ${userInfo.name}`, uid); @@ -31,7 +31,7 @@ class UserController { } static async updateName(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { name } = req.body; if (!isUsernameValid(name)) return res.status(400).json({ @@ -49,7 +49,7 @@ class UserController { } static async clearPb(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; await UsersDAO.clearPb(uid); Logger.log("user_cleared_pbs", "", uid); return res.sendStatus(200); @@ -69,7 +69,7 @@ class UserController { } static async updateEmail(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { newEmail } = req.body; try { await UsersDAO.updateEmail(uid, newEmail); @@ -81,7 +81,7 @@ class UserController { } static async getUser(req, res) { - const { email, uid } = req.decodedToken; + const { email, uid } = req.ctx.decodedToken; let userInfo; try { userInfo = await UsersDAO.getUser(uid); @@ -126,7 +126,7 @@ class UserController { } static async linkDiscord(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; let requser; try { @@ -174,7 +174,7 @@ class UserController { } static async unlinkDiscord(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; let userInfo; try { userInfo = await UsersDAO.getUser(uid); @@ -191,7 +191,7 @@ class UserController { } static async addTag(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { tagName } = req.body; if (!isTagPresetNameValid(tagName)) return res.status(400).json({ @@ -203,14 +203,14 @@ class UserController { } static async clearTagPb(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { tagid } = req.body; await UsersDAO.removeTagPb(uid, tagid); return res.sendStatus(200); } static async editTag(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { tagid, newname } = req.body; if (!isTagPresetNameValid(newname)) return res.status(400).json({ @@ -222,21 +222,21 @@ class UserController { } static async removeTag(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { tagid } = req.body; await UsersDAO.removeTag(uid, tagid); return res.sendStatus(200); } static async getTags(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; let tags = await UsersDAO.getTags(uid); if (tags == undefined) tags = []; return res.status(200).json(tags); } static async updateLbMemory(req, res) { - const { uid } = req.decodedToken; + const { uid } = req.ctx.decodedToken; const { mode, mode2, language, rank } = req.body; await UsersDAO.updateLbMemory(uid, mode, mode2, language, rank); return res.sendStatus(200); diff --git a/backend/api/routes/config.js b/backend/api/routes/config.js index 235bccdf5..a7b87a8b9 100644 --- a/backend/api/routes/config.js +++ b/backend/api/routes/config.js @@ -13,14 +13,14 @@ const router = Router(); router.get( "/", RateLimit.configGet, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(ConfigController.getConfig) ); router.post( "/save", RateLimit.configUpdate, - authenticateRequest, + authenticateRequest(), requestValidation({ body: { config: configSchema, diff --git a/backend/api/routes/leaderboards.js b/backend/api/routes/leaderboards.js index 99453e941..36de4a953 100644 --- a/backend/api/routes/leaderboards.js +++ b/backend/api/routes/leaderboards.js @@ -1,3 +1,4 @@ +const joi = require("joi"); const { authenticateRequest } = require("../../middlewares/auth"); const LeaderboardsController = require("../controllers/leaderboards"); const RateLimit = require("../../middlewares/rate-limit"); @@ -13,13 +14,32 @@ const router = Router(); router.get( "/", RateLimit.leaderboardsGet, + authenticateRequest({ isPublic: true }), + requestValidation({ + query: { + language: joi.string().required(), + mode: joi.string().required(), + mode2: joi.string().required(), + skip: joi.number().min(0).required(), + limit: joi.number(), + }, + validationErrorMessage: "Missing parameters", + }), asyncHandlerWrapper(LeaderboardsController.get) ); router.get( "/rank", RateLimit.leaderboardsGet, - authenticateRequest, + authenticateRequest(), + requestValidation({ + query: { + language: joi.string().required(), + mode: joi.string().required(), + mode2: joi.string().required(), + }, + validationErrorMessage: "Missing parameters", + }), asyncHandlerWrapper(LeaderboardsController.getRank) ); diff --git a/backend/api/routes/preset.js b/backend/api/routes/preset.js index c6c5cf12d..989dfbd1d 100644 --- a/backend/api/routes/preset.js +++ b/backend/api/routes/preset.js @@ -1,6 +1,8 @@ +const joi = require("joi"); const { authenticateRequest } = require("../../middlewares/auth"); const PresetController = require("../controllers/preset"); const RateLimit = require("../../middlewares/rate-limit"); +const configSchema = require("../schemas/config-schema"); const { asyncHandlerWrapper, requestValidation, @@ -10,31 +12,65 @@ const { Router } = require("express"); const router = Router(); +const presetNameSchema = joi + .string() + .required() + .regex(/^[0-9a-zA-Z_.-]+$/) + .max(16) + .messages({ + "string.pattern.base": "Invalid preset name", + "string.max": "Preset name exceeds maximum of 16 characters", + }); + router.get( "/", RateLimit.presetsGet, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(PresetController.getPresets) ); router.post( "/add", RateLimit.presetsAdd, - authenticateRequest, + authenticateRequest(), + requestValidation({ + body: { + name: presetNameSchema, + config: configSchema.keys({ + tags: joi.array().items(joi.string()), + }), + }, + }), asyncHandlerWrapper(PresetController.addPreset) ); router.post( "/edit", RateLimit.presetsEdit, - authenticateRequest, + authenticateRequest(), + requestValidation({ + body: { + _id: joi.string().required(), + name: presetNameSchema, + config: configSchema + .keys({ + tags: joi.array().items(joi.string()), + }) + .allow(null), + }, + }), asyncHandlerWrapper(PresetController.editPreset) ); router.post( "/remove", RateLimit.presetsRemove, - authenticateRequest, + authenticateRequest(), + requestValidation({ + body: { + _id: joi.string().required(), + }, + }), asyncHandlerWrapper(PresetController.removePreset) ); diff --git a/backend/api/routes/quotes.js b/backend/api/routes/quotes.js index 750e64a9d..f7017e063 100644 --- a/backend/api/routes/quotes.js +++ b/backend/api/routes/quotes.js @@ -17,7 +17,7 @@ const quotesRouter = Router(); quotesRouter.get( "/", RateLimit.newQuotesGet, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(NewQuotesController.getQuotes) ); @@ -31,7 +31,7 @@ quotesRouter.post( "Quote submission is disabled temporarily. The queue is quite long and we need some time to catch up.", }), RateLimit.newQuotesAdd, - authenticateRequest, + authenticateRequest(), requestValidation({ body: { text: joi.string().min(60).required(), @@ -47,7 +47,7 @@ quotesRouter.post( quotesRouter.post( "/approve", RateLimit.newQuotesAction, - authenticateRequest, + authenticateRequest(), requestValidation({ body: { quoteId: joi.string().required(), @@ -62,7 +62,7 @@ quotesRouter.post( quotesRouter.post( "/reject", RateLimit.newQuotesAction, - authenticateRequest, + authenticateRequest(), requestValidation({ body: { quoteId: joi.string().required(), @@ -74,7 +74,7 @@ quotesRouter.post( quotesRouter.get( "/rating", RateLimit.quoteRatingsGet, - authenticateRequest, + authenticateRequest(), requestValidation({ query: { quoteId: joi.string().regex(/^\d+$/).required(), @@ -87,7 +87,7 @@ quotesRouter.get( quotesRouter.post( "/rating", RateLimit.quoteRatingsSubmit, - authenticateRequest, + authenticateRequest(), requestValidation({ body: { quoteId: joi.number().required(), @@ -107,7 +107,7 @@ quotesRouter.post( invalidMessage: "Quote reporting is unavailable.", }), RateLimit.quoteReportSubmit, - authenticateRequest, + authenticateRequest(), requestValidation({ body: { quoteId: joi.string().required(), diff --git a/backend/api/routes/result.js b/backend/api/routes/result.js index ee4b6f25b..a3267f1be 100644 --- a/backend/api/routes/result.js +++ b/backend/api/routes/result.js @@ -12,28 +12,28 @@ const router = Router(); router.get( "/", RateLimit.resultsGet, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(ResultController.getResults) ); router.post( "/add", RateLimit.resultsAdd, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(ResultController.addResult) ); router.post( "/updateTags", RateLimit.resultsTagsUpdate, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(ResultController.updateTags) ); router.post( "/deleteAll", RateLimit.resultsDeleteAll, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(ResultController.deleteAll) ); @@ -46,7 +46,7 @@ router.get( router.post( "/checkLeaderboardQualification", RateLimit.resultsLeaderboardQualificationGet, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(ResultController.checkLeaderboardQualification) ); diff --git a/backend/api/routes/user.js b/backend/api/routes/user.js index 41c14866f..0fcc274e3 100644 --- a/backend/api/routes/user.js +++ b/backend/api/routes/user.js @@ -12,14 +12,14 @@ const router = Router(); router.get( "/", RateLimit.userGet, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.getUser) ); router.post( "/signup", RateLimit.userSignup, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.createNewUser) ); @@ -32,84 +32,84 @@ router.post( router.post( "/delete", RateLimit.userDelete, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.deleteUser) ); router.post( "/updateName", RateLimit.userUpdateName, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.updateName) ); router.post( "/updateLbMemory", RateLimit.userUpdateLBMemory, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.updateLbMemory) ); router.post( "/updateEmail", RateLimit.userUpdateEmail, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.updateEmail) ); router.post( "/clearPb", RateLimit.userClearPB, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.clearPb) ); router.post( "/tags/add", RateLimit.userTagsAdd, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.addTag) ); router.get( "/tags", RateLimit.userTagsGet, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.getTags) ); router.post( "/tags/clearPb", RateLimit.userTagsClearPB, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.clearTagPb) ); router.post( "/tags/remove", RateLimit.userTagsRemove, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.removeTag) ); router.post( "/tags/edit", RateLimit.userTagsEdit, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.editTag) ); router.post( "/discord/link", RateLimit.userDiscordLink, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.linkDiscord) ); router.post( "/discord/unlink", RateLimit.userDiscordUnlink, - authenticateRequest, + authenticateRequest(), asyncHandlerWrapper(UserController.unlinkDiscord) ); diff --git a/backend/middlewares/api-utils.js b/backend/middlewares/api-utils.js index a3c6b22f1..c00a14ecd 100644 --- a/backend/middlewares/api-utils.js +++ b/backend/middlewares/api-utils.js @@ -10,7 +10,7 @@ function validateConfiguration(options) { const { criteria, invalidMessage } = options; return (req, res, next) => { - const configuration = req.context.configuration; + const configuration = req.ctx.configuration; const validated = criteria(configuration); if (!validated) { @@ -78,7 +78,7 @@ function requestValidation(validationSchema) { throw new MonkeyError( 500, validationErrorMessage ?? - `Invalid request: ${errorMessage} (value ${error.details[0].context.value})` + `${errorMessage} (${error.details[0].context.value})` ); } }); diff --git a/backend/middlewares/auth.js b/backend/middlewares/auth.js index d46862613..67328b6f3 100644 --- a/backend/middlewares/auth.js +++ b/backend/middlewares/auth.js @@ -1,47 +1,83 @@ const MonkeyError = require("../handlers/error"); const { verifyIdToken } = require("../handlers/auth"); -module.exports = { - async authenticateRequest(req, res, next) { +const DEFAULT_OPTIONS = { + isPublic: false, +}; + +function authenticateRequest(options = DEFAULT_OPTIONS) { + return async (req, _res, next) => { try { - if (process.env.MODE === "dev" && !req.headers.authorization) { - if (req.body.uid) { - req.decodedToken = { - uid: req.body.uid, - }; - console.log("Running authorization in dev mode"); - return next(); - } else { - throw new MonkeyError( - 400, - "Running authorization in dev mode but still no uid was provided" - ); - } - } - const { authorization } = req.headers; - if (!authorization) + const { authorization: authHeader } = req.headers; + let token = null; + + if (authHeader) { + token = await authenticateWithAuthHeader(authHeader); + } else if (options.isPublic) { + return next(); + } else if (process.env.MODE === "dev") { + token = authenticateWithBody(req.body); + } else { throw new MonkeyError( 401, "Unauthorized", `endpoint: ${req.baseUrl} no authorization header found` ); - const token = authorization.split(" "); - if (token[0].trim() !== "Bearer") - return next( - new MonkeyError(400, "Invalid Token", "Incorrect token type") - ); - try { - req.decodedToken = await verifyIdToken(token[1]); - } catch (err) { - if (err.message == "auth/id-token-expired") { - new MonkeyError(401, "Unauthorized", "Token expired"); - } else { - throw err; - } } - return next(); - } catch (e) { - return next(e); + + req.ctx.decodedToken = token; + } catch (error) { + return next(error); } - }, + + next(); + }; +} + +function authenticateWithBody(body) { + const { uid } = body; + + if (!uid) { + throw new MonkeyError( + 400, + "Running authorization in dev mode but still no uid was provided" + ); + } + + return { + uid, + }; +} + +async function authenticateWithAuthHeader(authHeader) { + const token = authHeader.split(" "); + + const authScheme = token[0].trim(); + const credentials = token[1]; + + if (authScheme === "Bearer") { + return await authenticateWithBearerToken(credentials); + } + + throw new MonkeyError( + 400, + "Unknown authentication scheme", + `The authentication scheme "${authScheme}" is not implemented.` + ); +} + +async function authenticateWithBearerToken(token) { + try { + return await verifyIdToken(token); + } catch (error) { + if (error.message.includes("auth/id-token-expired")) { + throw new MonkeyError(401, "Unauthorized", "Token expired"); + } else { + throw error; + } + } +} + +module.exports = { + authenticateRequest, }; diff --git a/backend/middlewares/context.js b/backend/middlewares/context.js index a4fc313b9..496fc828f 100644 --- a/backend/middlewares/context.js +++ b/backend/middlewares/context.js @@ -3,8 +3,11 @@ const ConfigurationDAO = require("../dao/configuration"); async function contextMiddleware(req, res, next) { const configuration = await ConfigurationDAO.getCachedConfiguration(true); - req.context = { + req.ctx = { configuration, + decodedToken: { + uid: null, + }, }; next(); diff --git a/backend/server.js b/backend/server.js index 3e3008c6d..129c9d871 100644 --- a/backend/server.js +++ b/backend/server.js @@ -26,10 +26,7 @@ app.set("trust proxy", 1); app.use(contextMiddleware); app.use((req, res, next) => { - if ( - process.env.MAINTENANCE === "true" || - req.context.configuration.maintenance - ) { + if (process.env.MAINTENANCE === "true" || req.ctx.configuration.maintenance) { res.status(503).json({ message: "Server is down for maintenance" }); } else { next(); @@ -53,8 +50,8 @@ app.use(function (e, req, res, _next) { //its a server error monkeyError = new MonkeyError(e.status, e.message, e.stack); } - if (!monkeyError.uid && req.decodedToken) { - monkeyError.uid = req.decodedToken.uid; + if (!monkeyError.uid && req.ctx?.decodedToken) { + monkeyError.uid = req.ctx.decodedToken.uid; } if (process.env.MODE !== "dev" && monkeyError.status > 400) { Logger.log(