diff --git a/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee b/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee index b6b65cc7a7..08aa4663f1 100644 --- a/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee +++ b/services/web/app/coffee/Features/TokenAccess/TokenAccessController.coffee @@ -3,6 +3,7 @@ AuthenticationController = require '../Authentication/AuthenticationController' TokenAccessHandler = require './TokenAccessHandler' Errors = require '../Errors/Errors' logger = require 'logger-sharelatex' +settings = require 'settings-sharelatex' module.exports = TokenAccessController = @@ -11,11 +12,16 @@ module.exports = TokenAccessController = return ProjectController.loadEditor(req, res, next) _tryHigherAccess: (token, userId, req, res, next) -> - TokenAccessHandler.findProjectWithHigherAccess token, userId, (err, project) -> + TokenAccessHandler.findProjectWithHigherAccess token, userId, (err, project, projectExists) -> if err? logger.err {err, token, userId}, "[TokenAccess] error finding project with higher access" return next(err) + if !projectExists and settings.overleaf + logger.log {token, userId}, + "[TokenAccess] no project found for this token" + # Project does not exist, but may be unimported - try it on v1 + return res.redirect(settings.overleaf.host + req.url) if !project? logger.log {token, userId}, "[TokenAccess] no project with higher access found for this user and token" diff --git a/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee b/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee index 9eb792e55b..ed7f51f0d7 100644 --- a/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee +++ b/services/web/app/coffee/Features/TokenAccess/TokenAccessHandler.coffee @@ -22,7 +22,7 @@ module.exports = TokenAccessHandler = 'publicAccesLevel': PublicAccessLevels.TOKEN_BASED }, {_id: 1, publicAccesLevel: 1, owner_ref: 1}, callback - findProjectWithHigherAccess: (token, userId, callback=(err, project)->) -> + findProjectWithHigherAccess: (token, userId, callback=(err, project, projectExists)->) -> Project.findOne { $or: [ {'tokens.readAndWrite': token}, @@ -32,12 +32,16 @@ module.exports = TokenAccessHandler = if err? return callback(err) if !project? - return callback(null, null) + return callback(null, null, false) # Project doesn't exist, so we handle differently projectId = project._id CollaboratorsHandler.isUserInvitedMemberOfProject userId, projectId, (err, isMember) -> if err? return callback(err) - callback(null, if isMember == true then project else null) + callback( + null, + if isMember == true then project else null, + true # Project does exist, but user doesn't have access + ) addReadOnlyUserToProject: (userId, projectId, callback=(err)->) -> userId = ObjectId(userId.toString()) diff --git a/services/web/test/acceptance/coffee/TokenAccessTests.coffee b/services/web/test/acceptance/coffee/TokenAccessTests.coffee index 0e2985f75a..b0fbd7a0a1 100644 --- a/services/web/test/acceptance/coffee/TokenAccessTests.coffee +++ b/services/web/test/acceptance/coffee/TokenAccessTests.coffee @@ -415,3 +415,13 @@ describe 'TokenAccess', -> try_content_access(@other2, @project_id, (response, body) => expect(body.privilegeLevel).to.equal false , done) + + describe 'unimported v1 project', -> + it 'should redirect to v1', (done) -> + unimportedV1Token = '123abc' + try_read_and_write_token_access(@owner, unimportedV1Token, (response, body) => + expect(response.statusCode).to.equal 302 + expect(response.headers.location).to.equal( + 'http://overleaf.test:5000/123abc' + ) + , done) diff --git a/services/web/test/acceptance/config/settings.test.coffee b/services/web/test/acceptance/config/settings.test.coffee index 4dd820f4a7..1ca1b55e48 100644 --- a/services/web/test/acceptance/config/settings.test.coffee +++ b/services/web/test/acceptance/config/settings.test.coffee @@ -105,3 +105,6 @@ module.exports = path: (params) -> "/universities/list/#{params.id}" '/institutions/domains': { baseUrl: v1Api.url, path: '/university/domains' } '/proxy/missing/baseUrl': path: '/foo/bar' + + overleaf: + host: "http://overleaf.test:5000" diff --git a/services/web/test/unit/coffee/TokenAccess/TokenAccessControllerTests.coffee b/services/web/test/unit/coffee/TokenAccess/TokenAccessControllerTests.coffee index 747822b896..0bdb6d59e6 100644 --- a/services/web/test/unit/coffee/TokenAccess/TokenAccessControllerTests.coffee +++ b/services/web/test/unit/coffee/TokenAccess/TokenAccessControllerTests.coffee @@ -30,6 +30,10 @@ describe "TokenAccessController", -> '../Authentication/AuthenticationController': @AuthenticationController = {} './TokenAccessHandler': @TokenAccessHandler = {} 'logger-sharelatex': {log: sinon.stub(), err: sinon.stub()} + 'settings-sharelatex': { + overleaf: + host: 'http://overleaf.test:5000' + } @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString()) @@ -231,6 +235,27 @@ describe "TokenAccessController", -> @AuthenticationController.getLoggedInUserId = sinon.stub().returns(@userId.toString()) + describe 'when project does not exist', -> + beforeEach -> + @req = new MockRequest() + @req.url = '/123abc' + @res = new MockResponse() + @res.redirect = sinon.stub() + @next = sinon.stub() + @req.params['read_and_write_token'] = '123abc' + @TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub() + .callsArgWith(1, null, null) + @TokenAccessHandler.findProjectWithHigherAccess = + sinon.stub() + .callsArgWith(2, null, @project, false) + @TokenAccessController.readAndWriteToken @req, @res, @next + + it 'should redirect to v1', (done) -> + expect(@res.redirect.callCount).to.equal 1 + expect(@res.redirect.firstCall.args[0]) + .to.equal 'http://overleaf.test:5000/123abc' + done() + describe 'when token access is off, but user has higher access anyway', -> beforeEach -> @req = new MockRequest() @@ -242,7 +267,7 @@ describe "TokenAccessController", -> .callsArgWith(1, null, null) @TokenAccessHandler.findProjectWithHigherAccess = sinon.stub() - .callsArgWith(2, null, @project) + .callsArgWith(2, null, @project, true) @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub() .callsArgWith(2, null) @ProjectController.loadEditor = sinon.stub() @@ -291,7 +316,7 @@ describe "TokenAccessController", -> .callsArgWith(1, null, null) @TokenAccessHandler.findProjectWithHigherAccess = sinon.stub() - .callsArgWith(2, null, null) + .callsArgWith(2, null, null, true) @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub() .callsArgWith(2, null) @ProjectController.loadEditor = sinon.stub() @@ -479,6 +504,27 @@ describe "TokenAccessController", -> describe 'when findProject does not find a project', -> beforeEach -> + describe 'when project does not exist', -> + beforeEach -> + @req = new MockRequest() + @req.url = '/123abc' + @res = new MockResponse() + @res.redirect = sinon.stub() + @next = sinon.stub() + @req.params['read_and_write_token'] = '123abc' + @TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub() + .callsArgWith(1, null, null) + @TokenAccessHandler.findProjectWithHigherAccess = + sinon.stub() + .callsArgWith(2, null, @project, false) + @TokenAccessController.readOnlyToken @req, @res, @next + + it 'should return a ProjectNotTokenAccessError', (done) -> + expect(@res.redirect.callCount).to.equal 1 + expect(@res.redirect.firstCall.args[0]) + .to.equal 'http://overleaf.test:5000/123abc' + done() + describe 'when token access is off, but user has higher access anyway', -> beforeEach -> @req = new MockRequest() @@ -490,7 +536,7 @@ describe "TokenAccessController", -> .callsArgWith(1, null, null) @TokenAccessHandler.findProjectWithHigherAccess = sinon.stub() - .callsArgWith(2, null, @project) + .callsArgWith(2, null, @project, true) @TokenAccessHandler.addReadAndWriteUserToProject = sinon.stub() .callsArgWith(2, null) @ProjectController.loadEditor = sinon.stub() @@ -538,7 +584,7 @@ describe "TokenAccessController", -> .callsArgWith(1, null, null) @TokenAccessHandler.findProjectWithHigherAccess = sinon.stub() - .callsArgWith(2, null, null) + .callsArgWith(2, null, null, true) @TokenAccessHandler.addReadOnlyUserToProject = sinon.stub() .callsArgWith(2, null) @ProjectController.loadEditor = sinon.stub()