From 81170d472d412bb5ba9d82f67476737af4e619f5 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Fri, 22 Sep 2017 14:54:35 +0100 Subject: [PATCH] Add token-access routes --- .../TokenAccess/TokenAccessController.coffee | 61 +++++++++++++++++++ .../TokenAccess/TokenAccessHandler.coffee | 54 ++++++++++++++++ services/web/app/coffee/router.coffee | 9 +++ 3 files changed, 124 insertions(+) create mode 100644 services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee create mode 100644 services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee diff --git a/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee b/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee new file mode 100644 index 0000000000..6520d15cbd --- /dev/null +++ b/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee @@ -0,0 +1,61 @@ +ProjectGetter = require "../Project/ProjectGetter" +ProjectEditorHandler = require "../Project/ProjectEditorHandler" +UserGetter = require "../User/UserGetter" +AuthenticationController = require '../Authentication/AuthenticationController' +logger = require 'logger-sharelatex' +TokenAccessHandler = require './TokenAccessHandler' + + +module.exports = TokenAccessController = + + readAndWriteToken: (req, res, next) -> + userId = AuthenticationController.getLoggedInUserId(req) + token = req.params['read_and_write_token'] + logger.log {userId, token}, "requesting read-and-write token access" + TokenAccessHandler.findProjectWithReadAndWriteToken token, (err, project) -> + if err? + logger.err {err, token, userId}, + "error getting project by readAndWrite token" + return next(err) + if !project? + logger.log {token, userId}, + "no project found for readAndWrite token" + return res.sendStatus(404) + logger.log {userId, projectId: project._id}, + "adding user to project with readAndWrite token" + TokenAccessHandler.addReadAndWriteUserToProject userId, project._id, (err) -> + if err? + logger.err {err, token, userId, projectId: project._id}, + "error adding user to project with readAndWrite token" + return next(err) + return res.redirect("/project/#{project._id}") + + readOnlyToken: (req, res, next) -> + userId = AuthenticationController.getLoggedInUserId(req) + token = req.params['read_only_token'] + logger.log {userId, token}, "requesting read-only token access" + TokenAccessHandler.findProjectWithReadOnlyToken token, (err, project) -> + if err? + logger.err {err, token, user_id: currentUserId}, + "error getting project by readOnly token" + return next(err) + if !project? + logger.log {token, userId}, + "no project found for readAndWrite token" + return res.sendStatus(404) + if !userId? + logger.log {userId, projectId: project._id}, + "adding anonymous user to project with readOnly token" + TokenAccessHandler.grantAnonymousUserTokenAccessViaSession(req, project._id) + return res.redirect("/project/#{project._id}") + else + logger.log {userId, projectId: project._id}, + "adding user to project with readOnly token" + TokenAccessHandler.addReadOnlyUserToProject userId, project._id, (err) -> + if err? + logger.err {err, token, userId, projectId: project._id}, + "error adding user to project with readAndWrite token" + return next(err) + res.redirect("/project/#{project._id}") + + diff --git a/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee b/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee new file mode 100644 index 0000000000..7b29bbe9bc --- /dev/null +++ b/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee @@ -0,0 +1,54 @@ +ProjectGetter = require '../Project/ProjectGetter' +Project = require('../../models/Project').Project +AuthenticationController = require '../Authentication/AuthenticationController' +PublicAccessLevels = require '../Authorization/PublicAccessLevels' +ObjectId = require("mongojs").ObjectId + +module.exports = TokenAccessHandler = + + findProjectWithReadOnlyToken: (token, callback=(err, project)->) -> + Project.findOne { + 'tokens.readOnly': token, + 'publicAccesLevel': PublicAccessLevels.TOKEN_BASED + }, {_id: 1}, (err, project) -> + return callback(err) if err? + callback(null, project) + + findProjectWithReadAndWriteToken: (token, callback=(err, project)->) -> + Project.findOne { + 'tokens.readAndWrite': token, + 'publicAccesLevel': PublicAccessLevels.TOKEN_BASED + }, {_id: 1}, (err, project) -> + return callback(err) if err? + callback(null, project) + + addReadOnlyUserToProject: (userId, projectId, callback=(err)->) -> + userId = ObjectId(userId.toString()) + projectId = ObjectId(projectId.toString()) + Project.update { + _id: projectId + }, { + $addToSet: {tokenAccessReadOnly_refs: userId} + }, (err) -> + callback(err) + + addReadAndWriteUserToProject: (userId, projectId, callback=(err)->) -> + userId = ObjectId(userId.toString()) + projectId = ObjectId(projectId.toString()) + Project.update { + _id: projectId + }, { + $addToSet: {tokenAccessReadAndWrite_refs: userId} + }, (err) -> + callback(err) + + grantAnonymousUserTokenAccessViaSession: (req, projectId) -> + if req.session? + if !req.session.anonReadOnlyTokenAccess? + req.session.anonReadOnlyTokenAccess = {} + req.session.anonReadOnlyTokenAccess[projectId.toString()] = true + + anonymousUserHasTokenAccessViaSession: (req, projectId) -> + req?.session?.anonReadOnlyTokenAccess?[projectId.toString()] == true + + diff --git a/services/web/app/coffee/router.coffee b/services/web/app/coffee/router.coffee index 2ebde53748..229cc3b847 100644 --- a/services/web/app/coffee/router.coffee +++ b/services/web/app/coffee/router.coffee @@ -44,6 +44,7 @@ SudoModeMiddlewear = require('./Features/SudoMode/SudoModeMiddlewear') AnalyticsRouter = require('./Features/Analytics/AnalyticsRouter') AnnouncementsController = require("./Features/Announcements/AnnouncementsController") LabelsController = require('./Features/Labels/LabelsController') +TokenAccessController = require('./Features/TokenAccess/TokenAccessController') logger = require("logger-sharelatex") _ = require("underscore") @@ -337,4 +338,12 @@ module.exports = class Router metrics.inc("client-side-error") res.sendStatus(204) + + webRouter.get '/read/:read_only_token([a-z]+)', + TokenAccessController.readOnlyToken + + webRouter.get '/:read_and_write_token([0-9]+[a-z]+)', + AuthenticationController.requireLogin(), + TokenAccessController.readAndWriteToken + webRouter.get '*', ErrorController.notFound