diff --git a/services/web/app/coffee/Features/SudoMode/SudoModeHandler.coffee b/services/web/app/coffee/Features/SudoMode/SudoModeHandler.coffee index 5ae92b17a9..004b63ccc2 100644 --- a/services/web/app/coffee/Features/SudoMode/SudoModeHandler.coffee +++ b/services/web/app/coffee/Features/SudoMode/SudoModeHandler.coffee @@ -18,6 +18,12 @@ module.exports = SudoModeHandler = logger.log {userId, duration}, "[SudoMode] activating sudo mode for user" rclient.set SudoModeHandler._buildKey(userId), '1', 'EX', duration, callback + clearSudoMode: (userId, callback=(err)->) -> + if !userId? + return callback(new Error('[SudoMode] user must be supplied')) + logger.log {userId}, "[SudoMode] clearing sudo mode for user" + rclient.del SudoModeHandler._buildKey(userId), callback + isSudoModeActive: (userId, callback=(err, isActive)->) -> if !userId? return callback(new Error('[SudoMode] user must be supplied')) diff --git a/services/web/app/coffee/Features/User/UserController.coffee b/services/web/app/coffee/Features/User/UserController.coffee index 50b02fc918..65000985e1 100644 --- a/services/web/app/coffee/Features/User/UserController.coffee +++ b/services/web/app/coffee/Features/User/UserController.coffee @@ -11,6 +11,7 @@ AuthenticationManager = require("../Authentication/AuthenticationManager") AuthenticationController = require('../Authentication/AuthenticationController') UserSessionsManager = require("./UserSessionsManager") UserUpdater = require("./UserUpdater") +SudoModeHandler = require('../SudoMode/SudoModeHandler') settings = require "settings-sharelatex" module.exports = UserController = @@ -118,6 +119,7 @@ module.exports = UserController = if err logger.err err: err, 'error destorying session' UserSessionsManager.untrackSession(user, sessionId) + SudoModeHandler.clearSudoMode(user._id) res.redirect '/login' register : (req, res, next = (error) ->)-> diff --git a/services/web/test/UnitTests/coffee/SudoMode/SudoModeHandlerTests.coffee b/services/web/test/UnitTests/coffee/SudoMode/SudoModeHandlerTests.coffee index 994d793323..e7f3ccd150 100644 --- a/services/web/test/UnitTests/coffee/SudoMode/SudoModeHandlerTests.coffee +++ b/services/web/test/UnitTests/coffee/SudoMode/SudoModeHandlerTests.coffee @@ -30,6 +30,7 @@ describe 'SudoModeHandler', -> beforeEach -> @rclient.set = sinon.stub().callsArgWith(4, null) + it 'should not produce an error', (done) -> @call (err) => expect(err).to.equal null @@ -43,6 +44,22 @@ describe 'SudoModeHandler', -> )).to.equal true done() + describe 'when user id is not supplied', -> + beforeEach -> + @call = (cb) => + @SudoModeHandler.activateSudoMode null, cb + + it 'should produce an error', (done) -> + @call (err) => + expect(err).to.not.equal null + expect(err).to.be.instanceof Error + done() + + it 'should not set value in redis', (done) -> + @call (err) => + expect(@rclient.set.callCount).to.equal 0 + done() + describe 'when rclient.set produces an error', -> beforeEach -> @rclient.set = sinon.stub().callsArgWith(4, new Error('woops')) @@ -53,6 +70,51 @@ describe 'SudoModeHandler', -> expect(err).to.be.instanceof Error done() + describe 'clearSudoMode', -> + beforeEach -> + @rclient.del = sinon.stub().callsArgWith(1, null) + @call = (cb) => + @SudoModeHandler.clearSudoMode @userId, cb + + it 'should not produce an error', (done) -> + @call (err) => + expect(err).to.equal null + done() + + it 'should delete key from redis', (done) -> + @call (err) => + expect(@rclient.del.callCount).to.equal 1 + expect(@rclient.del.calledWith( + 'SudoMode:{some_user_id}' + )).to.equal true + done() + + describe 'when rclient.del produces an error', -> + beforeEach -> + @rclient.del = sinon.stub().callsArgWith(1, new Error('woops')) + + it 'should produce an error', (done) -> + @call (err) => + expect(err).to.not.equal null + expect(err).to.be.instanceof Error + done() + + describe 'when user id is not supplied', -> + beforeEach -> + @call = (cb) => + @SudoModeHandler.clearSudoMode null, cb + + it 'should produce an error', (done) -> + @call (err) => + expect(err).to.not.equal null + expect(err).to.be.instanceof Error + done() + + it 'should not delete value in redis', (done) -> + @call (err) => + expect(@rclient.del.callCount).to.equal 0 + done() + describe 'isSudoModeActive', -> beforeEach -> @call = (cb) => @@ -108,3 +170,19 @@ describe 'SudoModeHandler', -> expect(err).to.be.instanceof Error expect(isActive).to.be.oneOf [null, undefined] done() + + describe 'when user id is not supplied', -> + beforeEach -> + @call = (cb) => + @SudoModeHandler.isSudoModeActive null, cb + + it 'should produce an error', (done) -> + @call (err) => + expect(err).to.not.equal null + expect(err).to.be.instanceof Error + done() + + it 'should not get value in redis', (done) -> + @call (err) => + expect(@rclient.get.callCount).to.equal 0 + done() diff --git a/services/web/test/UnitTests/coffee/User/UserControllerTests.coffee b/services/web/test/UnitTests/coffee/User/UserControllerTests.coffee index ecb33495c4..a71fe4bb91 100644 --- a/services/web/test/UnitTests/coffee/User/UserControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/User/UserControllerTests.coffee @@ -60,6 +60,8 @@ describe "UserController", -> trackSession: sinon.stub() untrackSession: sinon.stub() revokeAllUserSessions: sinon.stub().callsArgWith(2, null) + @SudoModeHandler = + clearSudoMode: sinon.stub() @UserController = SandboxedModule.require modulePath, requires: "./UserLocator": @UserLocator "./UserDeleter": @UserDeleter @@ -73,6 +75,7 @@ describe "UserController", -> "../Subscription/SubscriptionDomainHandler":@SubscriptionDomainHandler "./UserHandler":@UserHandler "./UserSessionsManager": @UserSessionsManager + "../SudoMode/SudoModeHandler": @SudoModeHandler "settings-sharelatex": @settings "logger-sharelatex": log:-> @@ -302,6 +305,17 @@ describe "UserController", -> @UserController.logout @req, @res + it 'should clear sudo-mode', (done) -> + @req.session.destroy = sinon.stub().callsArgWith(0) + @SudoModeHandler.clearSudoMode = sinon.stub() + @res.redirect = (url)=> + url.should.equal "/login" + @SudoModeHandler.clearSudoMode.callCount.should.equal 1 + @SudoModeHandler.clearSudoMode.calledWith(@user._id).should.equal true + done() + + @UserController.logout @req, @res + describe "register", -> beforeEach ->