2017-10-03 09:04:59 -04:00
|
|
|
should = require('chai').should()
|
|
|
|
SandboxedModule = require('sandboxed-module')
|
|
|
|
assert = require('assert')
|
|
|
|
path = require('path')
|
|
|
|
sinon = require('sinon')
|
|
|
|
modulePath = path.join __dirname, "../../../../app/js/Features/TokenAccess/TokenAccessController"
|
|
|
|
expect = require("chai").expect
|
|
|
|
ObjectId = require("mongojs").ObjectId
|
|
|
|
MockRequest = require('../helpers/MockRequest')
|
|
|
|
MockResponse = require('../helpers/MockResponse')
|
|
|
|
Errors = require "../../../../app/js/Features/Errors/Errors.js"
|
|
|
|
|
|
|
|
describe "TokenAccessController", ->
|
|
|
|
|
|
|
|
beforeEach ->
|
|
|
|
@readOnlyToken = 'somereadonlytoken'
|
|
|
|
@readAndWriteToken = '42somereadandwritetoken'
|
|
|
|
@projectId = ObjectId()
|
2017-10-16 11:44:20 -04:00
|
|
|
@ownerId = 'owner'
|
2017-10-03 09:04:59 -04:00
|
|
|
@project =
|
|
|
|
_id: @projectId
|
|
|
|
publicAccesLevel: 'tokenBased'
|
|
|
|
tokens:
|
|
|
|
readOnly: @readOnlyToken
|
|
|
|
readAndWrite: @readAndWriteToken
|
2017-10-16 11:44:20 -04:00
|
|
|
owner_ref: @ownerId
|
2017-10-03 09:04:59 -04:00
|
|
|
@userId = ObjectId()
|
|
|
|
@TokenAccessController = SandboxedModule.require modulePath, requires:
|
|
|
|
'../Project/ProjectController': @ProjectController = {}
|
|
|
|
'../Authentication/AuthenticationController': @AuthenticationController = {}
|
|
|
|
'./TokenAccessHandler': @TokenAccessHandler = {}
|
|
|
|
'logger-sharelatex': {log: sinon.stub(), err: sinon.stub()}
|
|
|
|
|
|
|
|
@AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
|
|
|
|
|
|
|
|
|
|
|
|
describe 'readAndWriteToken', ->
|
|
|
|
beforeEach ->
|
|
|
|
|
|
|
|
describe 'when all goes well', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, @project)
|
|
|
|
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should add the user to the project with read-write access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
|
|
|
|
@userId.toString(), @projectId
|
|
|
|
))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should pass control to loadEditor', (done) ->
|
|
|
|
expect(@req.params.Project_id).to.equal @projectId.toString()
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 1
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
|
|
|
|
done()
|
|
|
|
|
2017-10-16 11:44:20 -04:00
|
|
|
describe 'when the user is already the owner', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@project.owner_ref = @userId
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, @project)
|
|
|
|
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-write access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should pass control to loadEditor', (done) ->
|
|
|
|
expect(@req.params.Project_id).to.equal @projectId.toString()
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 1
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
|
|
|
|
done()
|
|
|
|
|
2017-10-03 09:04:59 -04:00
|
|
|
|
2017-11-01 12:22:23 -04:00
|
|
|
describe 'when there is no user', ->
|
2017-10-03 09:04:59 -04:00
|
|
|
beforeEach ->
|
2017-11-01 12:22:23 -04:00
|
|
|
@AuthenticationController.getLoggedInUserId =
|
|
|
|
sinon.stub().returns(null)
|
2017-10-03 09:04:59 -04:00
|
|
|
|
2017-11-01 12:22:23 -04:00
|
|
|
describe 'when anonymous read-write access is enabled', ->
|
2017-10-16 08:20:15 -04:00
|
|
|
beforeEach ->
|
2017-11-01 12:22:23 -04:00
|
|
|
@TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = true
|
2017-10-16 08:20:15 -04:00
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
2017-11-01 12:22:23 -04:00
|
|
|
.callsArgWith(1, null, @project)
|
2017-10-16 08:20:15 -04:00
|
|
|
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
2017-11-01 12:22:23 -04:00
|
|
|
@TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
|
2017-10-16 08:20:15 -04:00
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-write access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
2017-11-01 12:22:23 -04:00
|
|
|
it 'should give the user session token access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
|
|
|
|
@req, @projectId, @readAndWriteToken
|
|
|
|
))
|
|
|
|
.to.equal true
|
2017-10-16 08:20:15 -04:00
|
|
|
done()
|
|
|
|
|
2017-11-01 12:22:23 -04:00
|
|
|
it 'should pass control to loadEditor', (done) ->
|
|
|
|
expect(@req.params.Project_id).to.equal @projectId.toString()
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 1
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
|
2017-10-16 08:20:15 -04:00
|
|
|
done()
|
|
|
|
|
2017-11-01 12:22:23 -04:00
|
|
|
describe 'when anonymous read-write access is not enabled', ->
|
2017-10-16 08:20:15 -04:00
|
|
|
beforeEach ->
|
2017-11-01 12:22:23 -04:00
|
|
|
@TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED = false
|
2017-10-16 08:20:15 -04:00
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
2017-11-06 11:46:42 -05:00
|
|
|
@res.redirect = sinon.stub()
|
2017-10-16 08:20:15 -04:00
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
2017-11-01 12:22:23 -04:00
|
|
|
.callsArgWith(1, null, @project)
|
2017-10-16 08:20:15 -04:00
|
|
|
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
2017-11-01 12:22:23 -04:00
|
|
|
@TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
|
2017-10-16 08:20:15 -04:00
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-write access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
2017-11-01 12:22:23 -04:00
|
|
|
it 'should give the user session token access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
2017-10-16 08:20:15 -04:00
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
2017-11-06 11:46:42 -05:00
|
|
|
it 'should redirect to restricted page', (done) ->
|
|
|
|
expect(@res.redirect.callCount).to.equal 1
|
|
|
|
expect(@res.redirect.calledWith('/restricted')).to.equal true
|
2017-10-16 08:20:15 -04:00
|
|
|
done()
|
2017-10-03 09:04:59 -04:00
|
|
|
|
2017-11-01 12:22:23 -04:00
|
|
|
describe 'when findProject produces an error', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
|
|
|
.callsArgWith(1, new Error('woops'))
|
|
|
|
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-write access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should call next with an error', (done) ->
|
|
|
|
expect(@next.callCount).to.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
done()
|
|
|
|
|
|
|
|
describe 'when findProject does not find a project', ->
|
|
|
|
beforeEach ->
|
|
|
|
|
|
|
|
describe 'when user is present', ->
|
|
|
|
beforeEach ->
|
|
|
|
@AuthenticationController.getLoggedInUserId =
|
|
|
|
sinon.stub().returns(@userId.toString())
|
|
|
|
|
|
|
|
describe 'when token access is off, but user has higher access anyway', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@res.redirect = sinon.stub()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, null)
|
|
|
|
@TokenAccessHandler.findProjectWithHigherAccess =
|
|
|
|
sinon.stub()
|
|
|
|
.callsArgWith(2, null, @project)
|
|
|
|
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken
|
|
|
|
.calledWith(@readAndWriteToken)
|
|
|
|
).to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should check if user has higher access to the token project', (done) ->
|
|
|
|
expect(
|
|
|
|
@TokenAccessHandler.findProjectWithHigherAccess.callCount
|
|
|
|
).to.equal 1
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-write access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not call next with a not-found error', (done) ->
|
|
|
|
expect(@next.callCount).to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should redirect to the canonical project url', (done) ->
|
|
|
|
expect(@res.redirect.callCount).to.equal 1
|
|
|
|
expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
describe 'when higher access is not available', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, null)
|
|
|
|
@TokenAccessHandler.findProjectWithHigherAccess =
|
|
|
|
sinon.stub()
|
|
|
|
.callsArgWith(2, null, null)
|
|
|
|
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
|
|
|
|
@readAndWriteToken
|
|
|
|
)).to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should check if user has higher access to the token project', (done) ->
|
|
|
|
expect(
|
|
|
|
@TokenAccessHandler.findProjectWithHigherAccess.callCount
|
|
|
|
).to.equal 1
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-write access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should call next with a not-found error', (done) ->
|
|
|
|
expect(@next.callCount).to.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
done()
|
|
|
|
|
2017-10-03 09:04:59 -04:00
|
|
|
describe 'when adding user to project produces an error', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, @project)
|
|
|
|
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, new Error('woops'))
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should add the user to the project with read-write access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.calledWith(
|
|
|
|
@userId.toString(), @projectId
|
|
|
|
))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should call next with an error', (done) ->
|
|
|
|
expect(@next.callCount).to.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
done()
|
|
|
|
|
|
|
|
|
|
|
|
describe 'readOnlyToken', ->
|
|
|
|
beforeEach ->
|
|
|
|
|
|
|
|
describe 'with a user', ->
|
|
|
|
beforeEach ->
|
|
|
|
@AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString())
|
|
|
|
|
|
|
|
describe 'when all goes well', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_only_token'] = @readOnlyToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, @project)
|
|
|
|
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should add the user to the project with read-only access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
|
|
|
|
@userId.toString(), @projectId
|
|
|
|
))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should pass control to loadEditor', (done) ->
|
|
|
|
expect(@req.params.Project_id).to.equal @projectId.toString()
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 1
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
|
|
|
|
done()
|
2017-10-16 11:44:20 -04:00
|
|
|
|
|
|
|
describe 'when the user is already the owner', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_only_token'] = @readOnlyToken
|
|
|
|
@project.owner_ref = @userId
|
|
|
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, @project)
|
|
|
|
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-only access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should pass control to loadEditor', (done) ->
|
|
|
|
expect(@req.params.Project_id).to.equal @projectId.toString()
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 1
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
|
|
|
|
done()
|
|
|
|
|
2017-10-03 09:04:59 -04:00
|
|
|
describe 'when findProject produces an error', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_only_token'] = @readOnlyToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
|
|
|
.callsArgWith(1, new Error('woops'))
|
|
|
|
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-only access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should call next with an error', (done) ->
|
|
|
|
expect(@next.callCount).to.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
done()
|
|
|
|
|
2017-11-01 10:01:00 -04:00
|
|
|
##
|
|
|
|
describe 'when findProject does not find a project', ->
|
|
|
|
beforeEach ->
|
|
|
|
|
|
|
|
describe 'when token access is off, but user has higher access anyway', ->
|
2017-10-03 09:04:59 -04:00
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
2017-11-01 10:01:00 -04:00
|
|
|
@res.redirect = sinon.stub()
|
2017-10-03 09:04:59 -04:00
|
|
|
@next = sinon.stub()
|
2017-11-01 10:01:00 -04:00
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
2017-10-03 09:04:59 -04:00
|
|
|
.callsArgWith(1, null, null)
|
2017-11-01 10:01:00 -04:00
|
|
|
@TokenAccessHandler.findProjectWithHigherAccess =
|
|
|
|
sinon.stub()
|
|
|
|
.callsArgWith(2, null, @project)
|
|
|
|
@TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub()
|
2017-10-03 09:04:59 -04:00
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
2017-11-01 10:01:00 -04:00
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
2017-10-03 09:04:59 -04:00
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
2017-11-01 10:01:00 -04:00
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
2017-10-03 09:04:59 -04:00
|
|
|
.to.equal 1
|
2017-11-01 10:01:00 -04:00
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(@readAndWriteToken))
|
2017-10-03 09:04:59 -04:00
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
2017-11-01 10:01:00 -04:00
|
|
|
it 'should check if user has higher access to the token project', (done) ->
|
|
|
|
expect(
|
|
|
|
@TokenAccessHandler.findProjectWithHigherAccess.callCount
|
|
|
|
).to.equal 1
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-write access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadAndWriteUserToProject.callCount)
|
2017-10-03 09:04:59 -04:00
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
2017-11-01 10:01:00 -04:00
|
|
|
it 'should not call next with a not-found error', (done) ->
|
|
|
|
expect(@next.callCount).to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should redirect to the canonical project url', (done) ->
|
|
|
|
expect(@res.redirect.callCount).to.equal 1
|
|
|
|
expect(@res.redirect.calledWith(302, "/project/#{@project._id}")).to.equal true
|
2017-10-03 09:04:59 -04:00
|
|
|
done()
|
|
|
|
|
2017-11-01 10:01:00 -04:00
|
|
|
describe 'when higher access is not available', ->
|
2017-10-03 09:04:59 -04:00
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
2017-11-01 10:01:00 -04:00
|
|
|
@req.params['read_and_write_token'] = @readAndWriteToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, null)
|
|
|
|
@TokenAccessHandler.findProjectWithHigherAccess =
|
|
|
|
sinon.stub()
|
|
|
|
.callsArgWith(2, null, null)
|
2017-10-03 09:04:59 -04:00
|
|
|
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
2017-11-01 10:01:00 -04:00
|
|
|
.callsArgWith(2, null)
|
2017-10-03 09:04:59 -04:00
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
2017-11-01 10:01:00 -04:00
|
|
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
2017-10-03 09:04:59 -04:00
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
2017-11-01 10:01:00 -04:00
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
2017-10-03 09:04:59 -04:00
|
|
|
.to.equal 1
|
2017-11-01 10:01:00 -04:00
|
|
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.calledWith(
|
|
|
|
@readAndWriteToken
|
|
|
|
)).to.equal true
|
2017-10-03 09:04:59 -04:00
|
|
|
done()
|
|
|
|
|
2017-11-01 10:01:00 -04:00
|
|
|
it 'should check if user has higher access to the token project', (done) ->
|
|
|
|
expect(
|
|
|
|
@TokenAccessHandler.findProjectWithHigherAccess.callCount
|
|
|
|
).to.equal 1
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-write access', (done) ->
|
2017-10-03 09:04:59 -04:00
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
|
2017-11-01 10:01:00 -04:00
|
|
|
.to.equal 0
|
2017-10-03 09:04:59 -04:00
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
2017-11-01 10:01:00 -04:00
|
|
|
it 'should call next with a not-found error', (done) ->
|
2017-10-03 09:04:59 -04:00
|
|
|
expect(@next.callCount).to.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
done()
|
|
|
|
|
2017-11-01 10:01:00 -04:00
|
|
|
describe 'when adding user to project produces an error', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_only_token'] = @readOnlyToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, @project)
|
|
|
|
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, new Error('woops'))
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should add the user to the project with read-only access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.calledWith(
|
|
|
|
@userId.toString(), @projectId
|
|
|
|
))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
2017-10-03 09:04:59 -04:00
|
|
|
|
2017-11-01 10:01:00 -04:00
|
|
|
it 'should call next with an error', (done) ->
|
|
|
|
expect(@next.callCount).to.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
done()
|
2017-10-03 09:04:59 -04:00
|
|
|
|
|
|
|
describe 'anonymous', ->
|
|
|
|
beforeEach ->
|
|
|
|
@AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
|
2017-10-18 08:04:37 -04:00
|
|
|
@TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
|
2017-10-03 09:04:59 -04:00
|
|
|
|
|
|
|
describe 'when all goes well', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_only_token'] = @readOnlyToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, @project)
|
|
|
|
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should give the user session read-only access', (done) ->
|
2017-10-18 08:04:37 -04:00
|
|
|
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
|
2017-10-03 09:04:59 -04:00
|
|
|
.to.equal 1
|
2017-10-18 08:04:37 -04:00
|
|
|
expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
|
2017-10-03 09:04:59 -04:00
|
|
|
@req, @projectId, @readOnlyToken
|
|
|
|
))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-only access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should pass control to loadEditor', (done) ->
|
|
|
|
expect(@req.params.Project_id).to.equal @projectId.toString()
|
2017-10-20 05:10:21 -04:00
|
|
|
expect(@req._anonymousAccessToken).to.equal @readOnlyToken
|
2017-10-03 09:04:59 -04:00
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 1
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
describe 'when findProject produces an error', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_only_token'] = @readOnlyToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
|
|
|
.callsArgWith(1, new Error('woops'))
|
|
|
|
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not give the user session read-only access', (done) ->
|
2017-10-18 08:04:37 -04:00
|
|
|
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
|
2017-10-03 09:04:59 -04:00
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-only access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should call next with an error', (done) ->
|
|
|
|
expect(@next.callCount).to.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
done()
|
|
|
|
|
|
|
|
describe 'when findProject does not find a project', ->
|
|
|
|
beforeEach ->
|
|
|
|
@req = new MockRequest()
|
|
|
|
@res = new MockResponse()
|
|
|
|
@next = sinon.stub()
|
|
|
|
@req.params['read_only_token'] = @readOnlyToken
|
|
|
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
|
|
|
.callsArgWith(1, null, null)
|
|
|
|
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
|
|
|
.callsArgWith(2, null)
|
|
|
|
@ProjectController.loadEditor = sinon.stub()
|
|
|
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
|
|
|
|
|
|
|
it 'should try to find a project with this token', (done) ->
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
|
|
|
.to.equal 1
|
|
|
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.calledWith(@readOnlyToken))
|
|
|
|
.to.equal true
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not give the user session read-only access', (done) ->
|
2017-10-18 08:04:37 -04:00
|
|
|
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
|
2017-10-03 09:04:59 -04:00
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not pass control to loadEditor', (done) ->
|
|
|
|
expect(@ProjectController.loadEditor.callCount).to.equal 0
|
|
|
|
expect(@ProjectController.loadEditor.calledWith(@req, @res, @next)).to.equal false
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should not add the user to the project with read-only access', (done) ->
|
|
|
|
expect(@TokenAccessHandler.addReadOnlyUserToProject.callCount)
|
|
|
|
.to.equal 0
|
|
|
|
done()
|
|
|
|
|
|
|
|
it 'should call next with a not-found error', (done) ->
|
|
|
|
expect(@next.callCount).to.equal 1
|
|
|
|
expect(@next.lastCall.args[0]).to.be.instanceof Error
|
|
|
|
done()
|
|
|
|
|