| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- 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/TokenAccessHandler"
- expect = require("chai").expect
- ObjectId = require("mongojs").ObjectId
- describe "TokenAccessHandler", ->
- beforeEach ->
- @token = 'sometokenthing'
- @projectId = ObjectId()
- @project =
- _id: @projectId
- publicAccesLevel: 'tokenBased'
- @userId = ObjectId()
- @req = {}
- @TokenAccessHandler = SandboxedModule.require modulePath, requires:
- '../../models/Project': {Project: @Project = {}}
- 'settings-sharelatex': {}
- '../Collaborators/CollaboratorsHandler': @CollaboratorsHandler = {}
- describe 'findProjectWithReadOnlyToken', ->
- beforeEach ->
- @Project.findOne = sinon.stub().callsArgWith(2, null, @project)
- it 'should call Project.findOne', (done) ->
- @TokenAccessHandler.findProjectWithReadOnlyToken @token, (err, project) =>
- expect(@Project.findOne.callCount).to.equal 1
- expect(@Project.findOne.calledWith({
- 'tokens.readOnly': @token,
- 'publicAccesLevel': 'tokenBased'
- })).to.equal true
- done()
- it 'should produce a project object with no error', (done) ->
- @TokenAccessHandler.findProjectWithReadOnlyToken @token, (err, project) =>
- expect(err).to.not.exist
- expect(project).to.exist
- expect(project).to.deep.equal @project
- done()
- describe 'when Project.findOne produces an error', ->
- beforeEach ->
- @Project.findOne = sinon.stub().callsArgWith(2, new Error('woops'))
- it 'should produce an error', (done) ->
- @TokenAccessHandler.findProjectWithReadOnlyToken @token, (err, project) =>
- expect(err).to.exist
- expect(project).to.not.exist
- expect(err).to.be.instanceof Error
- done()
- describe 'findProjectWithReadAndWriteToken', ->
- beforeEach ->
- @Project.findOne = sinon.stub().callsArgWith(2, null, @project)
- it 'should call Project.findOne', (done) ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken @token, (err, project) =>
- expect(@Project.findOne.callCount).to.equal 1
- expect(@Project.findOne.calledWith({
- 'tokens.readAndWrite': @token,
- 'publicAccesLevel': 'tokenBased'
- })).to.equal true
- done()
- it 'should produce a project object with no error', (done) ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken @token, (err, project) =>
- expect(err).to.not.exist
- expect(project).to.exist
- expect(project).to.deep.equal @project
- done()
- describe 'when Project.findOne produces an error', ->
- beforeEach ->
- @Project.findOne = sinon.stub().callsArgWith(2, new Error('woops'))
- it 'should produce an error', (done) ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken @token, (err, project) =>
- expect(err).to.exist
- expect(project).to.not.exist
- expect(err).to.be.instanceof Error
- done()
- describe 'findProjectWithHigherAccess', ->
- describe 'when user does have higher access', ->
- beforeEach ->
- @Project.findOne = sinon.stub().callsArgWith(2, null, @project)
- @CollaboratorsHandler.isUserInvitedMemberOfProject = sinon.stub()
- .callsArgWith(2, null, true)
- it 'should call Project.findOne', (done) ->
- @TokenAccessHandler.findProjectWithHigherAccess @token, @userId, (err, project) =>
- expect(@Project.findOne.callCount).to.equal 1
- expect(@Project.findOne.calledWith($or: [
- {'tokens.readAndWrite': @token},
- {'tokens.readOnly': @token}
- ])).to.equal true
- done()
- it 'should call isUserInvitedMemberOfProject', (done) ->
- @TokenAccessHandler.findProjectWithHigherAccess @token, @userId, (err, project) =>
- expect(@CollaboratorsHandler.isUserInvitedMemberOfProject.callCount)
- .to.equal 1
- expect(@CollaboratorsHandler.isUserInvitedMemberOfProject.calledWith(
- @userId, @project._id
- )).to.equal true
- done()
- it 'should produce a project object', (done) ->
- @TokenAccessHandler.findProjectWithHigherAccess @token, @userId, (err, project) =>
- expect(err).to.not.exist
- expect(project).to.exist
- expect(project).to.deep.equal @project
- done()
- describe 'when user does not have higher access', ->
- beforeEach ->
- @Project.findOne = sinon.stub().callsArgWith(2, null, @project)
- @CollaboratorsHandler.isUserInvitedMemberOfProject = sinon.stub()
- .callsArgWith(2, null, false)
- it 'should call Project.findOne', (done) ->
- @TokenAccessHandler.findProjectWithHigherAccess @token, @userId, (err, project) =>
- expect(@Project.findOne.callCount).to.equal 1
- expect(@Project.findOne.calledWith($or: [
- {'tokens.readAndWrite': @token},
- {'tokens.readOnly': @token}
- ])).to.equal true
- done()
- it 'should call isUserInvitedMemberOfProject', (done) ->
- @TokenAccessHandler.findProjectWithHigherAccess @token, @userId, (err, project) =>
- expect(@CollaboratorsHandler.isUserInvitedMemberOfProject.callCount)
- .to.equal 1
- expect(@CollaboratorsHandler.isUserInvitedMemberOfProject.calledWith(
- @userId, @project._id
- )).to.equal true
- done()
- it 'should not produce a project', (done) ->
- @TokenAccessHandler.findProjectWithHigherAccess @token, @userId, (err, project) =>
- expect(err).to.not.exist
- expect(project).to.not.exist
- done()
- describe 'when Project.findOne produces an error', ->
- beforeEach ->
- @Project.findOne = sinon.stub().callsArgWith(2, new Error('woops'))
- it 'should produce an error', (done) ->
- @TokenAccessHandler.findProjectWithHigherAccess @token, @userId, (err, project) =>
- expect(err).to.exist
- expect(project).to.not.exist
- expect(err).to.be.instanceof Error
- done()
- describe 'when isUserInvitedMemberOfProject produces an error', ->
- beforeEach ->
- @Project.findOne = sinon.stub().callsArgWith(2, null, @project)
- @CollaboratorsHandler.isUserInvitedMemberOfProject = sinon.stub()
- .callsArgWith(2, new Error('woops'))
- it 'should produce an error', (done) ->
- @TokenAccessHandler.findProjectWithHigherAccess @token, @userId, (err, project) =>
- expect(err).to.exist
- expect(project).to.not.exist
- expect(err).to.be.instanceof Error
- done()
- describe 'addReadOnlyUserToProject', ->
- beforeEach ->
- @Project.update = sinon.stub().callsArgWith(2, null)
- it 'should call Project.update', (done) ->
- @TokenAccessHandler.addReadOnlyUserToProject @userId, @projectId, (err) =>
- expect(@Project.update.callCount).to.equal 1
- expect(@Project.update.calledWith({
- _id: @projectId
- })).to.equal true
- expect(@Project.update.lastCall.args[1]['$addToSet'])
- .to.have.keys 'tokenAccessReadOnly_refs'
- done()
- it 'should not produce an error', (done) ->
- @TokenAccessHandler.addReadOnlyUserToProject @userId, @projectId, (err) =>
- expect(err).to.not.exist
- done()
- describe 'when Project.update produces an error', ->
- beforeEach ->
- @Project.update = sinon.stub().callsArgWith(2, new Error('woops'))
- it 'should produce an error', (done) ->
- @TokenAccessHandler.addReadOnlyUserToProject @userId, @projectId, (err) =>
- expect(err).to.exist
- done()
- describe 'addReadAndWriteUserToProject', ->
- beforeEach ->
- @Project.update = sinon.stub().callsArgWith(2, null)
- it 'should call Project.update', (done) ->
- @TokenAccessHandler.addReadAndWriteUserToProject @userId, @projectId, (err) =>
- expect(@Project.update.callCount).to.equal 1
- expect(@Project.update.calledWith({
- _id: @projectId
- })).to.equal true
- expect(@Project.update.lastCall.args[1]['$addToSet'])
- .to.have.keys 'tokenAccessReadAndWrite_refs'
- done()
- it 'should not produce an error', (done) ->
- @TokenAccessHandler.addReadAndWriteUserToProject @userId, @projectId, (err) =>
- expect(err).to.not.exist
- done()
- describe 'when Project.update produces an error', ->
- beforeEach ->
- @Project.update = sinon.stub().callsArgWith(2, new Error('woops'))
- it 'should produce an error', (done) ->
- @TokenAccessHandler.addReadAndWriteUserToProject @userId, @projectId, (err) =>
- expect(err).to.exist
- done()
- describe 'grantSessionTokenAccess', ->
- beforeEach ->
- @req = {session: {}, headers: {}}
- it 'should add the token to the session', (done) ->
- @TokenAccessHandler.grantSessionTokenAccess(@req, @projectId, @token)
- expect(@req.session.anonTokenAccess[@projectId.toString()])
- .to.equal @token
- done()
- describe 'isValidToken', ->
- describe 'when a read-only project is found', ->
- beforeEach ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
- .callsArgWith(1, null, null)
- @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
- .callsArgWith(1, null, @project)
- it 'should try to find projects with both kinds of token', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, allowed) =>
- expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
- .to.equal 1
- expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
- .to.equal 1
- done()
- it 'should allow read-only access', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
- expect(err).to.not.exist
- expect(rw).to.equal false
- expect(ro).to.equal true
- done()
- describe 'when a read-and-write project is found', ->
- beforeEach ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
- .callsArgWith(1, null, @project)
- @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
- .callsArgWith(1, null, null)
- it 'should try to find projects with both kinds of token', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, allowed) =>
- expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
- .to.equal 1
- expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
- .to.equal 1
- done()
- it 'should allow read-and-write access', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
- expect(err).to.not.exist
- expect(rw).to.equal true
- expect(ro).to.equal false
- done()
- describe 'when no project is found', ->
- beforeEach ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
- .callsArgWith(1, null, null)
- @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
- .callsArgWith(1, null, null)
- it 'should try to find projects with both kinds of token', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, allowed) =>
- expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
- .to.equal 1
- expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
- .to.equal 1
- done()
- it 'should not allow any access', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
- expect(err).to.not.exist
- expect(rw).to.equal false
- expect(ro).to.equal false
- done()
- describe 'when findProject produces an error', ->
- beforeEach ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
- .callsArgWith(1, null, null)
- @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
- .callsArgWith(1, new Error('woops'))
- it 'should try to find projects with both kinds of token', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, allowed) =>
- expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
- .to.equal 1
- expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
- .to.equal 1
- done()
- it 'should produce an error and not allow access', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
- expect(err).to.exist
- expect(err).to.be.instanceof Error
- expect(rw).to.equal undefined
- expect(ro).to.equal undefined
- done()
- describe 'when project is not set to token-based access', ->
- beforeEach ->
- @project.publicAccesLevel = 'private'
- describe 'for read-and-write project', ->
- beforeEach ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
- .callsArgWith(1, null, @project)
- @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
- .callsArgWith(1, null, null)
- it 'should try to find projects with both kinds of token', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, allowed) =>
- expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
- .to.equal 1
- expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
- .to.equal 1
- done()
- it 'should not allow any access', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
- expect(err).to.not.exist
- expect(rw).to.equal false
- expect(ro).to.equal false
- done()
- describe 'for read-only project', ->
- beforeEach ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
- .callsArgWith(1, null, null)
- @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
- .callsArgWith(1, null, @project)
- it 'should try to find projects with both kinds of token', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, allowed) =>
- expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
- .to.equal 1
- expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
- .to.equal 1
- done()
- it 'should not allow any access', (done) ->
- @TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
- expect(err).to.not.exist
- expect(rw).to.equal false
- expect(ro).to.equal false
- done()
- describe 'with nothing', ->
- beforeEach ->
- @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
- .callsArgWith(1, null, @project)
- @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
- .callsArgWith(1, null, null)
- it 'should not call findProjectWithReadOnlyToken', (done) ->
- @TokenAccessHandler.isValidToken @projectId, null, (err, allowed) =>
- expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
- .to.equal 0
- done()
- it 'should try to find projects with both kinds of token', (done) ->
- @TokenAccessHandler.isValidToken @projectId, null, (err, allowed) =>
- expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
- .to.equal 0
- expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
- .to.equal 0
- done()
- it 'should not allow any access', (done) ->
- @TokenAccessHandler.isValidToken @projectId, null, (err, rw, ro) =>
- expect(err).to.not.exist
- expect(rw).to.equal false
- expect(ro).to.equal false
- done()
- describe 'protectTokens', ->
- beforeEach ->
- @project = {tokens: {readAndWrite: 'rw', readOnly: 'ro'}}
- it 'should hide write token from read-only user', ->
- @TokenAccessHandler.protectTokens(@project, 'readOnly')
- expect(@project.tokens.readAndWrite).to.equal ''
- expect(@project.tokens.readOnly).to.equal 'ro'
- it 'should hide read token from read-write user', ->
- @TokenAccessHandler.protectTokens(@project, 'readAndWrite')
- expect(@project.tokens.readAndWrite).to.equal 'rw'
- expect(@project.tokens.readOnly).to.equal ''
- it 'should leave tokens in place for owner', ->
- @TokenAccessHandler.protectTokens(@project, 'owner')
- expect(@project.tokens.readAndWrite).to.equal 'rw'
- expect(@project.tokens.readOnly).to.equal 'ro'
|