2017-05-10 10:15:57 -04:00
|
|
|
SandboxedModule = require('sandboxed-module')
|
|
|
|
sinon = require 'sinon'
|
|
|
|
should = require("chai").should()
|
2017-05-15 05:07:22 -04:00
|
|
|
expect = require('chai').expect
|
2017-05-10 10:15:57 -04:00
|
|
|
MockRequest = require "../helpers/MockRequest"
|
|
|
|
MockResponse = require "../helpers/MockResponse"
|
|
|
|
modulePath = '../../../../app/js/Features/SudoMode/SudoModeController'
|
|
|
|
|
|
|
|
describe 'SudoModeController', ->
|
|
|
|
beforeEach ->
|
|
|
|
@user =
|
|
|
|
_id: 'abcd'
|
|
|
|
email: 'user@example.com'
|
|
|
|
@UserGetter =
|
|
|
|
getUser: sinon.stub().callsArgWith(2, null, @user)
|
|
|
|
@SudoModeHandler =
|
|
|
|
isSudoModeActive: sinon.stub()
|
|
|
|
activateSudoMode: sinon.stub()
|
2017-05-15 05:07:22 -04:00
|
|
|
@AuthenticationController =
|
|
|
|
getLoggedInUserId: sinon.stub().returns(@user._id)
|
2017-05-15 05:56:43 -04:00
|
|
|
_getRediretFromSession: sinon.stub()
|
2017-05-15 05:07:22 -04:00
|
|
|
@AuthenticationManager =
|
|
|
|
authenticate: sinon.stub()
|
|
|
|
@UserGetter =
|
|
|
|
getUser: sinon.stub()
|
|
|
|
@SudoModeController = SandboxedModule.require modulePath, requires:
|
|
|
|
'logger-sharelatex': {log: sinon.stub(), err: sinon.stub()}
|
|
|
|
'./SudoModeHandler': @SudoModeHandler
|
|
|
|
'../Authentication/AuthenticationController': @AuthenticationController
|
|
|
|
'../Authentication/AuthenticationManager': @AuthenticationManager
|
|
|
|
'../../infrastructure/Mongoose': {mongo: {ObjectId: () -> 'some_object_id'}}
|
|
|
|
'../User/UserGetter': @UserGetter
|
|
|
|
|
|
|
|
describe 'sudoModePrompt', ->
|
|
|
|
beforeEach ->
|
|
|
|
@SudoModeHandler.isSudoModeActive = sinon.stub().callsArgWith(1, null, false)
|
2017-05-15 10:46:24 -04:00
|
|
|
@req = {externalAuthenticationSystemUsed: sinon.stub().returns(false)}
|
2017-05-15 05:07:22 -04:00
|
|
|
@res = {redirect: sinon.stub(), render: sinon.stub()}
|
|
|
|
@next = sinon.stub()
|
|
|
|
|
|
|
|
it 'should get the logged in user id', ->
|
|
|
|
@SudoModeController.sudoModePrompt(@req, @res, @next)
|
|
|
|
@AuthenticationController.getLoggedInUserId.callCount.should.equal 1
|
|
|
|
@AuthenticationController.getLoggedInUserId.calledWith(@req).should.equal true
|
|
|
|
|
|
|
|
it 'should check if sudo-mode is active', ->
|
|
|
|
@SudoModeController.sudoModePrompt(@req, @res, @next)
|
|
|
|
@SudoModeHandler.isSudoModeActive.callCount.should.equal 1
|
|
|
|
@SudoModeHandler.isSudoModeActive.calledWith(@user._id).should.equal true
|
|
|
|
|
|
|
|
it 'should redirect when sudo-mode is active', ->
|
|
|
|
@SudoModeHandler.isSudoModeActive = sinon.stub().callsArgWith(1, null, true)
|
|
|
|
@SudoModeController.sudoModePrompt(@req, @res, @next)
|
|
|
|
@res.redirect.callCount.should.equal 1
|
|
|
|
@res.redirect.calledWith('/project').should.equal true
|
|
|
|
|
|
|
|
it 'should render the sudo_mode_prompt page when sudo mode is not active', ->
|
|
|
|
@SudoModeHandler.isSudoModeActive = sinon.stub().callsArgWith(1, null, false)
|
|
|
|
@SudoModeController.sudoModePrompt(@req, @res, @next)
|
|
|
|
@res.render.callCount.should.equal 1
|
|
|
|
@res.render.calledWith('sudo_mode/sudo_mode_prompt').should.equal true
|
|
|
|
|
|
|
|
describe 'when isSudoModeActive produces an error', ->
|
|
|
|
beforeEach ->
|
|
|
|
@SudoModeHandler.isSudoModeActive = sinon.stub().callsArgWith(1, new Error('woops'))
|
|
|
|
@next = sinon.stub()
|
2017-05-10 10:15:57 -04:00
|
|
|
|
2017-05-15 05:07:22 -04:00
|
|
|
it 'should call next with an error', ->
|
|
|
|
@SudoModeController.sudoModePrompt(@req, @res, @next)
|
|
|
|
@next.callCount.should.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
2017-05-15 05:56:43 -04:00
|
|
|
|
2017-05-15 10:46:24 -04:00
|
|
|
it 'should not render page', ->
|
|
|
|
@SudoModeController.sudoModePrompt(@req, @res, @next)
|
|
|
|
@res.render.callCount.should.equal 0
|
|
|
|
|
|
|
|
describe 'when external auth system is used', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req.externalAuthenticationSystemUsed = sinon.stub().returns(true)
|
|
|
|
|
|
|
|
it 'should redirect', ->
|
|
|
|
@SudoModeController.sudoModePrompt(@req, @res, @next)
|
|
|
|
@res.redirect.callCount.should.equal 1
|
|
|
|
@res.redirect.calledWith('/project').should.equal true
|
|
|
|
|
|
|
|
it 'should not check if sudo mode is active', ->
|
|
|
|
@SudoModeController.sudoModePrompt(@req, @res, @next)
|
|
|
|
@SudoModeHandler.isSudoModeActive.callCount.should.equal 0
|
|
|
|
|
|
|
|
it 'should not render page', ->
|
|
|
|
@SudoModeController.sudoModePrompt(@req, @res, @next)
|
|
|
|
@res.render.callCount.should.equal 0
|
|
|
|
|
2017-05-15 05:56:43 -04:00
|
|
|
describe 'submitPassword', ->
|
|
|
|
beforeEach ->
|
|
|
|
@AuthenticationController._getRedirectFromSession = sinon.stub().returns '/somewhere'
|
|
|
|
@UserGetter.getUser = sinon.stub().callsArgWith(2, null, @user)
|
|
|
|
@AuthenticationManager.authenticate = sinon.stub().callsArgWith(2, null, @user)
|
|
|
|
@SudoModeHandler.activateSudoMode = sinon.stub().callsArgWith(1, null)
|
|
|
|
@password = 'a_terrible_secret'
|
|
|
|
@req = {body: {password: @password}}
|
|
|
|
@res = {json: sinon.stub()}
|
|
|
|
@next = sinon.stub()
|
|
|
|
|
|
|
|
describe 'when all goes well', ->
|
|
|
|
beforeEach ->
|
|
|
|
|
|
|
|
it 'should get the logged in user id', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@AuthenticationController.getLoggedInUserId.callCount.should.equal 1
|
|
|
|
@AuthenticationController.getLoggedInUserId.calledWith(@req).should.equal true
|
|
|
|
|
|
|
|
it 'should get redirect from session', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@AuthenticationController._getRedirectFromSession.callCount.should.equal 1
|
|
|
|
@AuthenticationController._getRedirectFromSession.calledWith(@req).should.equal true
|
|
|
|
|
|
|
|
it 'should get the user from storage', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@UserGetter.getUser.callCount.should.equal 1
|
|
|
|
@UserGetter.getUser.calledWith('some_object_id', {email: 1}).should.equal true
|
|
|
|
|
|
|
|
it 'should try to authenticate the user with the password', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@AuthenticationManager.authenticate.callCount.should.equal 1
|
|
|
|
@AuthenticationManager.authenticate.calledWith({email: @user.email}, @password).should.equal true
|
|
|
|
|
|
|
|
it 'should activate sudo mode', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@SudoModeHandler.activateSudoMode.callCount.should.equal 1
|
|
|
|
@SudoModeHandler.activateSudoMode.calledWith(@user._id).should.equal true
|
|
|
|
|
|
|
|
it 'should send back a json response', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@res.json.callCount.should.equal 1
|
|
|
|
@res.json.calledWith({redir: '/somewhere'}).should.equal true
|
|
|
|
|
|
|
|
it 'should not call next', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@next.callCount.should.equal 0
|
|
|
|
|
|
|
|
describe 'when no password is supplied', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req.body.password = ''
|
|
|
|
@next = sinon.stub()
|
|
|
|
|
|
|
|
it 'should return next with an error', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@next.callCount.should.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
|
|
|
|
it 'should not get the user from storage', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@UserGetter.getUser.callCount.should.equal 0
|
|
|
|
|
|
|
|
it 'should not try to authenticate the user with the password', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@AuthenticationManager.authenticate.callCount.should.equal 0
|
|
|
|
|
|
|
|
it 'should not activate sudo mode', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@SudoModeHandler.activateSudoMode.callCount.should.equal 0
|
|
|
|
|
|
|
|
it 'should not send back a json response', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@res.json.callCount.should.equal 0
|
|
|
|
|
|
|
|
describe 'when getUser produces an error', ->
|
|
|
|
beforeEach ->
|
|
|
|
@UserGetter.getUser = sinon.stub().callsArgWith(2, new Error('woops'))
|
|
|
|
@next = sinon.stub()
|
|
|
|
|
|
|
|
it 'should return next with an error', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@next.callCount.should.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
|
|
|
|
it 'should get the user from storage', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@UserGetter.getUser.callCount.should.equal 1
|
|
|
|
@UserGetter.getUser.calledWith('some_object_id', {email: 1}).should.equal true
|
|
|
|
|
|
|
|
it 'should not try to authenticate the user with the password', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@AuthenticationManager.authenticate.callCount.should.equal 0
|
|
|
|
|
|
|
|
it 'should not activate sudo mode', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@SudoModeHandler.activateSudoMode.callCount.should.equal 0
|
|
|
|
|
|
|
|
it 'should not send back a json response', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@res.json.callCount.should.equal 0
|
|
|
|
|
|
|
|
describe 'when getUser does not find a user', ->
|
|
|
|
beforeEach ->
|
|
|
|
@UserGetter.getUser = sinon.stub().callsArgWith(2, null, null)
|
|
|
|
@next = sinon.stub()
|
|
|
|
|
|
|
|
it 'should return next with an error', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@next.callCount.should.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
|
|
|
|
it 'should get the user from storage', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@UserGetter.getUser.callCount.should.equal 1
|
|
|
|
@UserGetter.getUser.calledWith('some_object_id', {email: 1}).should.equal true
|
|
|
|
|
|
|
|
it 'should not try to authenticate the user with the password', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@AuthenticationManager.authenticate.callCount.should.equal 0
|
|
|
|
|
|
|
|
it 'should not activate sudo mode', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@SudoModeHandler.activateSudoMode.callCount.should.equal 0
|
|
|
|
|
|
|
|
it 'should not send back a json response', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@res.json.callCount.should.equal 0
|
|
|
|
|
|
|
|
describe 'when authentication fails', ->
|
|
|
|
beforeEach ->
|
|
|
|
@AuthenticationManager.authenticate = sinon.stub().callsArgWith(2, null, null)
|
|
|
|
@res.json = sinon.stub()
|
|
|
|
@req.i18n = {translate: sinon.stub()}
|
|
|
|
|
|
|
|
it 'should send back a failure message', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@res.json.callCount.should.equal 1
|
|
|
|
expect(@res.json.lastCall.args[0]).to.have.keys ['message']
|
|
|
|
expect(@res.json.lastCall.args[0].message).to.have.keys ['text', 'type']
|
|
|
|
@req.i18n.translate.callCount.should.equal 1
|
|
|
|
@req.i18n.translate.calledWith('invalid_password')
|
|
|
|
|
|
|
|
it 'should get the user from storage', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@UserGetter.getUser.callCount.should.equal 1
|
|
|
|
@UserGetter.getUser.calledWith('some_object_id', {email: 1}).should.equal true
|
|
|
|
|
|
|
|
it 'should try to authenticate the user with the password', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@AuthenticationManager.authenticate.callCount.should.equal 1
|
|
|
|
@AuthenticationManager.authenticate.calledWith({email: @user.email}, @password).should.equal true
|
|
|
|
|
|
|
|
it 'should not activate sudo mode', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@SudoModeHandler.activateSudoMode.callCount.should.equal 0
|
|
|
|
|
|
|
|
describe 'when authentication produces an error', ->
|
|
|
|
beforeEach ->
|
|
|
|
@AuthenticationManager.authenticate = sinon.stub().callsArgWith(2, new Error('woops'))
|
|
|
|
@next = sinon.stub()
|
|
|
|
|
|
|
|
it 'should return next with an error', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@next.callCount.should.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
|
|
|
|
it 'should get the user from storage', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@UserGetter.getUser.callCount.should.equal 1
|
|
|
|
@UserGetter.getUser.calledWith('some_object_id', {email: 1}).should.equal true
|
|
|
|
|
|
|
|
it 'should try to authenticate the user with the password', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@AuthenticationManager.authenticate.callCount.should.equal 1
|
|
|
|
@AuthenticationManager.authenticate.calledWith({email: @user.email}, @password).should.equal true
|
|
|
|
|
|
|
|
it 'should not activate sudo mode', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@SudoModeHandler.activateSudoMode.callCount.should.equal 0
|
|
|
|
|
|
|
|
describe 'when sudo mode activation produces an error', ->
|
|
|
|
beforeEach ->
|
|
|
|
@SudoModeHandler.activateSudoMode = sinon.stub().callsArgWith(1, new Error('woops'))
|
|
|
|
@next = sinon.stub()
|
|
|
|
|
|
|
|
it 'should return next with an error', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@next.callCount.should.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
|
|
|
|
it 'should get the user from storage', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@UserGetter.getUser.callCount.should.equal 1
|
|
|
|
@UserGetter.getUser.calledWith('some_object_id', {email: 1}).should.equal true
|
|
|
|
|
|
|
|
it 'should try to authenticate the user with the password', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@AuthenticationManager.authenticate.callCount.should.equal 1
|
|
|
|
@AuthenticationManager.authenticate.calledWith({email: @user.email}, @password).should.equal true
|
|
|
|
|
|
|
|
it 'should have tried to activate sudo mode', ->
|
|
|
|
@SudoModeController.submitPassword(@req, @res, @next)
|
|
|
|
@SudoModeHandler.activateSudoMode.callCount.should.equal 1
|
|
|
|
@SudoModeHandler.activateSudoMode.calledWith(@user._id).should.equal true
|