mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-30 05:05:27 -05:00
Merge pull request #981 from sharelatex/as-fix-intelligent-redirect-loop
Prevent redirect loop if project was imported to v2 then deleted
This commit is contained in:
commit
052cbda507
5 changed files with 99 additions and 25 deletions
|
@ -1,6 +1,7 @@
|
||||||
ProjectController = require "../Project/ProjectController"
|
ProjectController = require "../Project/ProjectController"
|
||||||
AuthenticationController = require '../Authentication/AuthenticationController'
|
AuthenticationController = require '../Authentication/AuthenticationController'
|
||||||
TokenAccessHandler = require './TokenAccessHandler'
|
TokenAccessHandler = require './TokenAccessHandler'
|
||||||
|
V1Api = require '../V1/V1Api'
|
||||||
Errors = require '../Errors/Errors'
|
Errors = require '../Errors/Errors'
|
||||||
logger = require 'logger-sharelatex'
|
logger = require 'logger-sharelatex'
|
||||||
settings = require 'settings-sharelatex'
|
settings = require 'settings-sharelatex'
|
||||||
|
@ -36,9 +37,12 @@ module.exports = TokenAccessController =
|
||||||
return next(err)
|
return next(err)
|
||||||
if !projectExists and settings.overleaf
|
if !projectExists and settings.overleaf
|
||||||
logger.log {token, userId},
|
logger.log {token, userId},
|
||||||
"[TokenAccess] no project found for this token"
|
"[TokenAccess] no project found for this token"
|
||||||
return res.redirect(302, "/sign_in_to_v1?return_to=/#{token}")
|
TokenAccessHandler.checkV1ProjectExported token, (err, exported) ->
|
||||||
if !project?
|
return next err if err?
|
||||||
|
return next(new Errors.NotFoundError()) if exported
|
||||||
|
return res.redirect(302, "/sign_in_to_v1?return_to=/#{token}")
|
||||||
|
else if !project?
|
||||||
logger.log {token, userId},
|
logger.log {token, userId},
|
||||||
"[TokenAccess] no token-based project found for readAndWrite token"
|
"[TokenAccess] no token-based project found for readAndWrite token"
|
||||||
if !userId?
|
if !userId?
|
||||||
|
@ -83,9 +87,12 @@ module.exports = TokenAccessController =
|
||||||
return next(err)
|
return next(err)
|
||||||
if !projectExists and settings.overleaf
|
if !projectExists and settings.overleaf
|
||||||
logger.log {token, userId},
|
logger.log {token, userId},
|
||||||
"[TokenAccess] no project found for this token"
|
"[TokenAccess] no project found for this token"
|
||||||
return res.redirect(302, settings.overleaf.host + '/read/' + token)
|
TokenAccessHandler.checkV1ProjectExported token, (err, exported) ->
|
||||||
if !project?
|
return next err if err?
|
||||||
|
return next(new Errors.NotFoundError()) if exported
|
||||||
|
return res.redirect(302, "/sign_in_to_v1?return_to=/read/#{token}")
|
||||||
|
else if !project?
|
||||||
logger.log {token, userId},
|
logger.log {token, userId},
|
||||||
"[TokenAccess] no project found for readOnly token"
|
"[TokenAccess] no project found for readOnly token"
|
||||||
if !userId?
|
if !userId?
|
||||||
|
|
|
@ -116,3 +116,9 @@ module.exports = TokenAccessHandler =
|
||||||
return callback err if err?
|
return callback err if err?
|
||||||
callback null, false, body.published_path if body.allow == false
|
callback null, false, body.published_path if body.allow == false
|
||||||
callback null, true
|
callback null, true
|
||||||
|
|
||||||
|
checkV1ProjectExported: (token, callback = (err, exists) ->) ->
|
||||||
|
return callback(null, false) unless Settings.apis?.v1?
|
||||||
|
V1Api.request { url: "/api/v1/sharelatex/docs/#{token}/exported_to_v2" }, (err, response, body) ->
|
||||||
|
return callback err if err?
|
||||||
|
callback null, body.exported
|
||||||
|
|
|
@ -431,6 +431,6 @@ describe 'TokenAccess', ->
|
||||||
try_read_only_token_access(@owner, unimportedV1Token, (response, body) =>
|
try_read_only_token_access(@owner, unimportedV1Token, (response, body) =>
|
||||||
expect(response.statusCode).to.equal 302
|
expect(response.statusCode).to.equal 302
|
||||||
expect(response.headers.location).to.equal(
|
expect(response.headers.location).to.equal(
|
||||||
'http://overleaf.test:5000/read/abcd'
|
'/sign_in_to_v1?return_to=/read/abcd'
|
||||||
)
|
)
|
||||||
, done)
|
, done)
|
||||||
|
|
|
@ -85,4 +85,7 @@ module.exports = MockV1Api =
|
||||||
app.get '/api/v1/sharelatex/docs/:token/is_published', (req, res, next) =>
|
app.get '/api/v1/sharelatex/docs/:token/is_published', (req, res, next) =>
|
||||||
res.json { allow: true }
|
res.json { allow: true }
|
||||||
|
|
||||||
|
app.get '/api/v1/sharelatex/docs/:token/exported_to_v2', (req, res, next) =>
|
||||||
|
res.json { exported: false }
|
||||||
|
|
||||||
MockV1Api.run()
|
MockV1Api.run()
|
||||||
|
|
|
@ -248,18 +248,30 @@ describe "TokenAccessController", ->
|
||||||
@req.params['read_and_write_token'] = '123abc'
|
@req.params['read_and_write_token'] = '123abc'
|
||||||
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
||||||
.callsArgWith(1, null, null, false)
|
.callsArgWith(1, null, null, false)
|
||||||
@TokenAccessHandler.findProjectWithHigherAccess =
|
|
||||||
sinon.stub()
|
|
||||||
.callsArgWith(2, null, @project)
|
|
||||||
@TokenAccessController.readAndWriteToken @req, @res, @next
|
|
||||||
|
|
||||||
it 'should redirect to v1', (done) ->
|
describe 'when project was not exported from v1', ->
|
||||||
expect(@res.redirect.callCount).to.equal 1
|
beforeEach ->
|
||||||
expect(@res.redirect.calledWith(
|
@TokenAccessHandler.checkV1ProjectExported = sinon.stub()
|
||||||
302,
|
.callsArgWith(1, null, false)
|
||||||
'/sign_in_to_v1?return_to=/123abc'
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
||||||
)).to.equal true
|
|
||||||
done()
|
it 'should redirect to v1', (done) ->
|
||||||
|
expect(@res.redirect.callCount).to.equal 1
|
||||||
|
expect(@res.redirect.calledWith(
|
||||||
|
302,
|
||||||
|
'/sign_in_to_v1?return_to=/123abc'
|
||||||
|
)).to.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
describe 'when project was exported from v1', ->
|
||||||
|
beforeEach ->
|
||||||
|
@TokenAccessHandler.checkV1ProjectExported = sinon.stub()
|
||||||
|
.callsArgWith(1, null, false)
|
||||||
|
@TokenAccessController.readAndWriteToken @req, @res, @next
|
||||||
|
|
||||||
|
it 'should call next with a not-found error', (done) ->
|
||||||
|
expect(@next.callCount).to.equal 0
|
||||||
|
done()
|
||||||
|
|
||||||
describe 'when token access is off, but user has higher access anyway', ->
|
describe 'when token access is off, but user has higher access anyway', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
@ -521,6 +533,44 @@ describe "TokenAccessController", ->
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe 'when findProject does not find a project', ->
|
describe 'when findProject does not find a project', ->
|
||||||
|
describe 'when project does not exist', ->
|
||||||
|
beforeEach ->
|
||||||
|
@req = new MockRequest()
|
||||||
|
@res = new MockResponse()
|
||||||
|
@res.redirect = sinon.stub()
|
||||||
|
@next = sinon.stub()
|
||||||
|
@req.params['read_only_token'] = 'abcd'
|
||||||
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
||||||
|
.callsArgWith(1, null, null, false)
|
||||||
|
@TokenAccessHandler.checkV1ProjectExported = sinon.stub()
|
||||||
|
.callsArgWith(1, null, false)
|
||||||
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
||||||
|
|
||||||
|
it 'should redirect to v1', (done) ->
|
||||||
|
expect(@res.redirect.callCount).to.equal 1
|
||||||
|
expect(@res.redirect.calledWith(
|
||||||
|
302,
|
||||||
|
'/sign_in_to_v1?return_to=/read/abcd'
|
||||||
|
)).to.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
describe 'when project was exported from v1', ->
|
||||||
|
beforeEach ->
|
||||||
|
@req = new MockRequest()
|
||||||
|
@res = new MockResponse()
|
||||||
|
@res.redirect = sinon.stub()
|
||||||
|
@next = sinon.stub()
|
||||||
|
@req.params['read_only_token'] = 'abcd'
|
||||||
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
||||||
|
.callsArgWith(1, null, null, false)
|
||||||
|
@TokenAccessHandler.checkV1ProjectExported = sinon.stub()
|
||||||
|
.callsArgWith(1, null, true)
|
||||||
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
||||||
|
|
||||||
|
it 'should call next with a not-found error', (done) ->
|
||||||
|
expect(@next.callCount).to.equal 1
|
||||||
|
done()
|
||||||
|
|
||||||
describe 'when token access is off, but user has higher access anyway', ->
|
describe 'when token access is off, but user has higher access anyway', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@req = new MockRequest()
|
@req = new MockRequest()
|
||||||
|
@ -749,6 +799,8 @@ describe "TokenAccessController", ->
|
||||||
@req.params['read_only_token'] = @readOnlyToken
|
@req.params['read_only_token'] = @readOnlyToken
|
||||||
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
||||||
.callsArgWith(1, null, null)
|
.callsArgWith(1, null, null)
|
||||||
|
@TokenAccessHandler.checkV1ProjectExported = sinon.stub()
|
||||||
|
.callsArgWith(1, null, false)
|
||||||
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
@TokenAccessHandler.addReadOnlyUserToProject = sinon.stub()
|
||||||
.callsArgWith(2, null)
|
.callsArgWith(2, null)
|
||||||
@ProjectController.loadEditor = sinon.stub()
|
@ProjectController.loadEditor = sinon.stub()
|
||||||
|
@ -776,11 +828,17 @@ describe "TokenAccessController", ->
|
||||||
.to.equal 0
|
.to.equal 0
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'should redirect to v1', (done) ->
|
describe 'when project was exported to v2', ->
|
||||||
expect(@res.redirect.callCount).to.equal 1
|
beforeEach ->
|
||||||
expect(@res.redirect.calledWith(
|
@TokenAccessHandler.checkV1ProjectExported = sinon.stub()
|
||||||
302,
|
.callsArgWith(1, null, true)
|
||||||
"http://overleaf.test:5000/read/#{@readOnlyToken}"
|
@TokenAccessController.readOnlyToken @req, @res, @next
|
||||||
)).to.equal true
|
|
||||||
done()
|
it 'should redirect to v1', (done) ->
|
||||||
|
expect(@res.redirect.callCount).to.equal 1
|
||||||
|
expect(@res.redirect.calledWith(
|
||||||
|
302,
|
||||||
|
"/sign_in_to_v1?return_to=/read/#{@readOnlyToken}"
|
||||||
|
)).to.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue