/* eslint-disable node/handle-callback-err, max-len, no-return-assign, no-unused-vars, */ // TODO: This file was created by bulk-decaffeinate. // Fix any style issues and re-enable lint. /* * decaffeinate suggestions: * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ const sinon = require('sinon') const { expect } = require('chai') const modulePath = '../../../../app/src/Features/Authorization/AuthorizationManager.js' const SandboxedModule = require('sandboxed-module') const Errors = require('../../../../app/src/Features/Errors/Errors.js') const { ObjectId } = require('mongodb') describe('AuthorizationManager', function () { beforeEach(function () { this.AuthorizationManager = SandboxedModule.require(modulePath, { requires: { mongodb: { ObjectId }, '../Collaborators/CollaboratorsGetter': (this.CollaboratorsGetter = {}), '../Collaborators/CollaboratorsHandler': (this.CollaboratorsHandler = {}), '../Project/ProjectGetter': (this.ProjectGetter = {}), '../../models/User': { User: (this.User = {}) }, '../TokenAccess/TokenAccessHandler': (this.TokenAccessHandler = { validateTokenForAnonymousAccess: sinon .stub() .callsArgWith(2, null, false, false) }), 'settings-sharelatex': { passwordStrengthOptions: {} } } }) this.user_id = 'user-id-1' this.project_id = 'project-id-1' this.token = 'some-token' return (this.callback = sinon.stub()) }) describe('isRestrictedUser', function () { it('should produce the correct values', function () { const notRestrictedScenarios = [ [null, 'readAndWrite', false], ['id', 'readAndWrite', true], ['id', 'readOnly', false] ] const restrictedScenarios = [ [null, 'readOnly', false], ['id', 'readOnly', true], [null, false, true], [null, false, false], ['id', false, true], ['id', false, false] ] for (var notRestrictedArgs of notRestrictedScenarios) { expect( this.AuthorizationManager.isRestrictedUser(...notRestrictedArgs) ).to.equal(false) } for (var restrictedArgs of restrictedScenarios) { expect( this.AuthorizationManager.isRestrictedUser(...restrictedArgs) ).to.equal(true) } }) }) describe('getPrivilegeLevelForProject', function () { beforeEach(function () { this.ProjectGetter.getProject = sinon.stub() this.AuthorizationManager.isUserSiteAdmin = sinon.stub() return (this.CollaboratorsGetter.getMemberIdPrivilegeLevel = sinon.stub()) }) describe('with a token-based project', function () { beforeEach(function () { return this.ProjectGetter.getProject .withArgs(this.project_id, { publicAccesLevel: 1 }) .yields(null, { publicAccesLevel: 'tokenBased' }) }) describe('with a user_id with a privilege level', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, false) this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, 'readOnly') return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, this.callback ) }) it("should return the user's privilege level", function () { return this.callback .calledWith(null, 'readOnly', false, false) .should.equal(true) }) }) describe('with a user_id with no privilege level', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, false) this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, false) return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, this.callback ) }) it('should return false', function () { return this.callback .calledWith(null, false, false, false) .should.equal(true) }) }) describe('with a user_id who is an admin', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, true) this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, false) return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, this.callback ) }) it('should return the user as an owner', function () { return this.callback .calledWith(null, 'owner', false, true) .should.equal(true) }) }) describe('with no user (anonymous)', function () { describe('when the token is not valid', function () { beforeEach(function () { this.TokenAccessHandler.validateTokenForAnonymousAccess = sinon .stub() .withArgs(this.project_id, this.token) .yields(null, false, false) return this.AuthorizationManager.getPrivilegeLevelForProject( null, this.project_id, this.token, this.callback ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { return this.CollaboratorsGetter.getMemberIdPrivilegeLevel.called.should.equal( false ) }) it('should not call AuthorizationManager.isUserSiteAdmin', function () { return this.AuthorizationManager.isUserSiteAdmin.called.should.equal( false ) }) it('should check if the token is valid', function () { return this.TokenAccessHandler.validateTokenForAnonymousAccess .calledWith(this.project_id, this.token) .should.equal(true) }) it('should return false', function () { return this.callback .calledWith(null, false, false, false) .should.equal(true) }) }) describe('when the token is valid for read-and-write', function () { beforeEach(function () { this.TokenAccessHandler.validateTokenForAnonymousAccess = sinon .stub() .withArgs(this.project_id, this.token) .yields(null, true, false) return this.AuthorizationManager.getPrivilegeLevelForProject( null, this.project_id, this.token, this.callback ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { return this.CollaboratorsGetter.getMemberIdPrivilegeLevel.called.should.equal( false ) }) it('should not call AuthorizationManager.isUserSiteAdmin', function () { return this.AuthorizationManager.isUserSiteAdmin.called.should.equal( false ) }) it('should check if the token is valid', function () { return this.TokenAccessHandler.validateTokenForAnonymousAccess .calledWith(this.project_id, this.token) .should.equal(true) }) it('should give read-write access', function () { return this.callback .calledWith(null, 'readAndWrite', false) .should.equal(true) }) }) describe('when the token is valid for read-only', function () { beforeEach(function () { this.TokenAccessHandler.validateTokenForAnonymousAccess = sinon .stub() .withArgs(this.project_id, this.token) .yields(null, false, true) return this.AuthorizationManager.getPrivilegeLevelForProject( null, this.project_id, this.token, this.callback ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { return this.CollaboratorsGetter.getMemberIdPrivilegeLevel.called.should.equal( false ) }) it('should not call AuthorizationManager.isUserSiteAdmin', function () { return this.AuthorizationManager.isUserSiteAdmin.called.should.equal( false ) }) it('should check if the token is valid', function () { return this.TokenAccessHandler.validateTokenForAnonymousAccess .calledWith(this.project_id, this.token) .should.equal(true) }) it('should give read-only access', function () { return this.callback .calledWith(null, 'readOnly', false) .should.equal(true) }) }) }) }) describe('with a private project', function () { beforeEach(function () { return this.ProjectGetter.getProject .withArgs(this.project_id, { publicAccesLevel: 1 }) .yields(null, { publicAccesLevel: 'private' }) }) describe('with a user_id with a privilege level', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, false) this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, 'readOnly') return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, this.callback ) }) it("should return the user's privilege level", function () { return this.callback .calledWith(null, 'readOnly', false, false) .should.equal(true) }) }) describe('with a user_id with no privilege level', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, false) this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, false) return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, this.callback ) }) it('should return false', function () { return this.callback .calledWith(null, false, false, false) .should.equal(true) }) }) describe('with a user_id who is an admin', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, true) this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, false) return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, this.callback ) }) it('should return the user as an owner', function () { return this.callback .calledWith(null, 'owner', false, true) .should.equal(true) }) }) describe('with no user (anonymous)', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject( null, this.project_id, this.token, this.callback ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { return this.CollaboratorsGetter.getMemberIdPrivilegeLevel.called.should.equal( false ) }) it('should not call AuthorizationManager.isUserSiteAdmin', function () { return this.AuthorizationManager.isUserSiteAdmin.called.should.equal( false ) }) it('should return false', function () { return this.callback .calledWith(null, false, false, false) .should.equal(true) }) }) }) describe('with a public project', function () { beforeEach(function () { return this.ProjectGetter.getProject .withArgs(this.project_id, { publicAccesLevel: 1 }) .yields(null, { publicAccesLevel: 'readAndWrite' }) }) describe('with a user_id with a privilege level', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, false) this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, 'readOnly') return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, this.callback ) }) it("should return the user's privilege level", function () { return this.callback .calledWith(null, 'readOnly', false) .should.equal(true) }) }) describe('with a user_id with no privilege level', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, false) this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, false) return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, this.callback ) }) it('should return the public privilege level', function () { return this.callback .calledWith(null, 'readAndWrite', true) .should.equal(true) }) }) describe('with a user_id who is an admin', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, true) this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, false) return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, this.callback ) }) it('should return the user as an owner', function () { return this.callback .calledWith(null, 'owner', false) .should.equal(true) }) }) describe('with no user (anonymous)', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject( null, this.project_id, this.token, this.callback ) }) it('should not call CollaboratorsGetter.getMemberIdPrivilegeLevel', function () { return this.CollaboratorsGetter.getMemberIdPrivilegeLevel.called.should.equal( false ) }) it('should not call AuthorizationManager.isUserSiteAdmin', function () { return this.AuthorizationManager.isUserSiteAdmin.called.should.equal( false ) }) it('should return the public privilege level', function () { return this.callback .calledWith(null, 'readAndWrite', true) .should.equal(true) }) }) }) describe("when the project doesn't exist", function () { beforeEach(function () { return this.ProjectGetter.getProject .withArgs(this.project_id, { publicAccesLevel: 1 }) .yields(null, null) }) it('should return a NotFoundError', function () { return this.AuthorizationManager.getPrivilegeLevelForProject( this.user_id, this.project_id, this.token, error => error.should.be.instanceof(Errors.NotFoundError) ) }) }) describe('when the project id is not valid', function () { beforeEach(function () { this.AuthorizationManager.isUserSiteAdmin .withArgs(this.user_id) .yields(null, false) return this.CollaboratorsGetter.getMemberIdPrivilegeLevel .withArgs(this.user_id, this.project_id) .yields(null, 'readOnly') }) it('should return a error', function (done) { return this.AuthorizationManager.getPrivilegeLevelForProject( undefined, 'not project id', this.token, err => { this.ProjectGetter.getProject.called.should.equal(false) expect(err).to.exist return done() } ) }) }) }) describe('canUserReadProject', function () { beforeEach(function () { return (this.AuthorizationManager.getPrivilegeLevelForProject = sinon.stub()) }) describe('when user is owner', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'owner', false) }) it('should return true', function (done) { return this.AuthorizationManager.canUserReadProject( this.user_id, this.project_id, this.token, (error, canRead) => { expect(canRead).to.equal(true) return done() } ) }) }) describe('when user has read-write access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'readAndWrite', false) }) it('should return true', function (done) { return this.AuthorizationManager.canUserReadProject( this.user_id, this.project_id, this.token, (error, canRead) => { expect(canRead).to.equal(true) return done() } ) }) }) describe('when user has read-only access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'readOnly', false) }) it('should return true', function (done) { return this.AuthorizationManager.canUserReadProject( this.user_id, this.project_id, this.token, (error, canRead) => { expect(canRead).to.equal(true) return done() } ) }) }) describe('when user has no access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, false, false) }) it('should return false', function (done) { return this.AuthorizationManager.canUserReadProject( this.user_id, this.project_id, this.token, (error, canRead) => { expect(canRead).to.equal(false) return done() } ) }) }) }) describe('canUserWriteProjectContent', function () { beforeEach(function () { return (this.AuthorizationManager.getPrivilegeLevelForProject = sinon.stub()) }) describe('when user is owner', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'owner', false) }) it('should return true', function (done) { return this.AuthorizationManager.canUserWriteProjectContent( this.user_id, this.project_id, this.token, (error, canWrite) => { expect(canWrite).to.equal(true) return done() } ) }) }) describe('when user has read-write access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'readAndWrite', false) }) it('should return true', function (done) { return this.AuthorizationManager.canUserWriteProjectContent( this.user_id, this.project_id, this.token, (error, canWrite) => { expect(canWrite).to.equal(true) return done() } ) }) }) describe('when user has read-only access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'readOnly', false) }) it('should return false', function (done) { return this.AuthorizationManager.canUserWriteProjectContent( this.user_id, this.project_id, this.token, (error, canWrite) => { expect(canWrite).to.equal(false) return done() } ) }) }) describe('when user has no access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, false, false) }) it('should return false', function (done) { return this.AuthorizationManager.canUserWriteProjectContent( this.user_id, this.project_id, this.token, (error, canWrite) => { expect(canWrite).to.equal(false) return done() } ) }) }) }) describe('canUserWriteProjectSettings', function () { beforeEach(function () { return (this.AuthorizationManager.getPrivilegeLevelForProject = sinon.stub()) }) describe('when user is owner', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'owner', false) }) it('should return true', function (done) { return this.AuthorizationManager.canUserWriteProjectSettings( this.user_id, this.project_id, this.token, (error, canWrite) => { expect(canWrite).to.equal(true) return done() } ) }) }) describe('when user has read-write access as a collaborator', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'readAndWrite', false) }) it('should return true', function (done) { return this.AuthorizationManager.canUserWriteProjectSettings( this.user_id, this.project_id, this.token, (error, canWrite) => { expect(canWrite).to.equal(true) return done() } ) }) }) describe('when user has read-write access as the public', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'readAndWrite', true) }) it('should return false', function (done) { return this.AuthorizationManager.canUserWriteProjectSettings( this.user_id, this.project_id, this.token, (error, canWrite) => { expect(canWrite).to.equal(false) return done() } ) }) }) describe('when user has read-only access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'readOnly', false) }) it('should return false', function (done) { return this.AuthorizationManager.canUserWriteProjectSettings( this.user_id, this.project_id, this.token, (error, canWrite) => { expect(canWrite).to.equal(false) return done() } ) }) }) describe('when user has no access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, false, false) }) it('should return false', function (done) { return this.AuthorizationManager.canUserWriteProjectSettings( this.user_id, this.project_id, this.token, (error, canWrite) => { expect(canWrite).to.equal(false) return done() } ) }) }) }) describe('canUserAdminProject', function () { beforeEach(function () { return (this.AuthorizationManager.getPrivilegeLevelForProject = sinon.stub()) }) describe('when user is owner', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'owner', false) }) it('should return true', function (done) { return this.AuthorizationManager.canUserAdminProject( this.user_id, this.project_id, this.token, (error, canAdmin) => { expect(canAdmin).to.equal(true) return done() } ) }) }) describe('when user has read-write access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'readAndWrite', false) }) it('should return false', function (done) { return this.AuthorizationManager.canUserAdminProject( this.user_id, this.project_id, this.token, (error, canAdmin) => { expect(canAdmin).to.equal(false) return done() } ) }) }) describe('when user has read-only access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, 'readOnly', false) }) it('should return false', function (done) { return this.AuthorizationManager.canUserAdminProject( this.user_id, this.project_id, this.token, (error, canAdmin) => { expect(canAdmin).to.equal(false) return done() } ) }) }) describe('when user has no access', function () { beforeEach(function () { return this.AuthorizationManager.getPrivilegeLevelForProject .withArgs(this.user_id, this.project_id, this.token) .yields(null, false, false) }) it('should return false', function (done) { return this.AuthorizationManager.canUserAdminProject( this.user_id, this.project_id, this.token, (error, canAdmin) => { expect(canAdmin).to.equal(false) return done() } ) }) }) }) describe('isUserSiteAdmin', function () { beforeEach(function () { return (this.User.findOne = sinon.stub()) }) describe('when user is admin', function () { beforeEach(function () { return this.User.findOne .withArgs({ _id: this.user_id }, { isAdmin: 1 }) .yields(null, { isAdmin: true }) }) it('should return true', function (done) { return this.AuthorizationManager.isUserSiteAdmin( this.user_id, (error, isAdmin) => { expect(isAdmin).to.equal(true) return done() } ) }) }) describe('when user is not admin', function () { beforeEach(function () { return this.User.findOne .withArgs({ _id: this.user_id }, { isAdmin: 1 }) .yields(null, { isAdmin: false }) }) it('should return false', function (done) { return this.AuthorizationManager.isUserSiteAdmin( this.user_id, (error, isAdmin) => { expect(isAdmin).to.equal(false) return done() } ) }) }) describe('when user is not found', function () { beforeEach(function () { return this.User.findOne .withArgs({ _id: this.user_id }, { isAdmin: 1 }) .yields(null, null) }) it('should return false', function (done) { return this.AuthorizationManager.isUserSiteAdmin( this.user_id, (error, isAdmin) => { expect(isAdmin).to.equal(false) return done() } ) }) }) describe('when no user is passed', function () { it('should return false', function (done) { return this.AuthorizationManager.isUserSiteAdmin( null, (error, isAdmin) => { this.User.findOne.called.should.equal(false) expect(isAdmin).to.equal(false) return done() } ) }) }) }) })