mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Add a setting to enable anonymous read-and-write link sharing
This commit is contained in:
parent
9c247d5f59
commit
7d2bde85ff
9 changed files with 253 additions and 81 deletions
|
@ -35,14 +35,22 @@ module.exports = AuthorizationManager =
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
if publicAccessLevel == PublicAccessLevels.TOKEN_BASED
|
if publicAccessLevel == PublicAccessLevels.TOKEN_BASED
|
||||||
# Anonymous users can have read-only access to token-based projects,
|
# Anonymous users can have read-only access to token-based projects,
|
||||||
# while read-write access must be logged in
|
# while read-write access must be logged in,
|
||||||
TokenAccessHandler.isValidReadOnlyToken project_id, token, (err, isValid) ->
|
# unless the `enableAnonymousReadAndWriteSharing` setting is enabled
|
||||||
|
TokenAccessHandler.isValidToken project_id, token,
|
||||||
|
(err, isValidReadAndWrite, isValidReadOnly) ->
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
if isValid
|
if isValidReadOnly
|
||||||
# Grant anonymous user read-only access
|
# Grant anonymous user read-only access
|
||||||
callback null, PrivilegeLevels.READ_ONLY, false
|
callback null, PrivilegeLevels.READ_ONLY, false
|
||||||
|
else if (
|
||||||
|
isValidReadAndWrite and
|
||||||
|
TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED
|
||||||
|
)
|
||||||
|
# Grant anonymous user read-and-write access
|
||||||
|
callback null, PrivilegeLevels.READ_AND_WRITE, false
|
||||||
else
|
else
|
||||||
# Deny anonymous user access
|
# Deny anonymous access
|
||||||
callback null, PrivilegeLevels.NONE, false
|
callback null, PrivilegeLevels.NONE, false
|
||||||
else if publicAccessLevel == PublicAccessLevels.READ_ONLY
|
else if publicAccessLevel == PublicAccessLevels.READ_ONLY
|
||||||
# Legacy public read-only access for anonymous user
|
# Legacy public read-only access for anonymous user
|
||||||
|
|
|
@ -4,7 +4,6 @@ TokenAccessHandler = require './TokenAccessHandler'
|
||||||
Errors = require '../Errors/Errors'
|
Errors = require '../Errors/Errors'
|
||||||
logger = require 'logger-sharelatex'
|
logger = require 'logger-sharelatex'
|
||||||
|
|
||||||
|
|
||||||
module.exports = TokenAccessController =
|
module.exports = TokenAccessController =
|
||||||
|
|
||||||
_loadEditor: (projectId, req, res, next) ->
|
_loadEditor: (projectId, req, res, next) ->
|
||||||
|
@ -23,6 +22,10 @@ module.exports = TokenAccessController =
|
||||||
if !project?
|
if !project?
|
||||||
logger.log {token, userId},
|
logger.log {token, userId},
|
||||||
"no project found for readAndWrite token"
|
"no project found for readAndWrite token"
|
||||||
|
if !userId?
|
||||||
|
logger.log {token},
|
||||||
|
"No project found with read-write token, anonymous user"
|
||||||
|
return next(new Errors.NotFoundError())
|
||||||
TokenAccessHandler
|
TokenAccessHandler
|
||||||
.findPrivateOverleafProjectWithReadAndWriteToken token, (err, project) ->
|
.findPrivateOverleafProjectWithReadAndWriteToken token, (err, project) ->
|
||||||
if err?
|
if err?
|
||||||
|
@ -36,6 +39,17 @@ module.exports = TokenAccessController =
|
||||||
logger.log {token, projectId: project._id}, "redirecting user to project"
|
logger.log {token, projectId: project._id}, "redirecting user to project"
|
||||||
res.redirect(302, "/project/#{project._id}")
|
res.redirect(302, "/project/#{project._id}")
|
||||||
else
|
else
|
||||||
|
if !userId?
|
||||||
|
if TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED
|
||||||
|
logger.log {token, projectId: project._id},
|
||||||
|
"allow anonymous read-and-write token access"
|
||||||
|
TokenAccessHandler.grantSessionTokenAccess(req, project._id, token)
|
||||||
|
req._anonToken = token
|
||||||
|
return TokenAccessController._loadEditor(project._id, req, res, next)
|
||||||
|
else
|
||||||
|
logger.log {token, projectId: project._id},
|
||||||
|
"deny anonymous read-and-write token access"
|
||||||
|
return next(new Errors.NotFoundError())
|
||||||
if project.owner_ref.toString() == userId
|
if project.owner_ref.toString() == userId
|
||||||
logger.log {userId, projectId: project._id},
|
logger.log {userId, projectId: project._id},
|
||||||
"user is already project owner"
|
"user is already project owner"
|
||||||
|
@ -65,7 +79,7 @@ module.exports = TokenAccessController =
|
||||||
if !userId?
|
if !userId?
|
||||||
logger.log {userId, projectId: project._id},
|
logger.log {userId, projectId: project._id},
|
||||||
"adding anonymous user to project with readOnly token"
|
"adding anonymous user to project with readOnly token"
|
||||||
TokenAccessHandler.grantSessionReadOnlyTokenAccess(req, project._id, token)
|
TokenAccessHandler.grantSessionTokenAccess(req, project._id, token)
|
||||||
req._anonToken = token
|
req._anonToken = token
|
||||||
return TokenAccessController._loadEditor(project._id, req, res, next)
|
return TokenAccessController._loadEditor(project._id, req, res, next)
|
||||||
else
|
else
|
||||||
|
@ -80,7 +94,6 @@ module.exports = TokenAccessController =
|
||||||
logger.err {err, token, userId, projectId: project._id},
|
logger.err {err, token, userId, projectId: project._id},
|
||||||
"error adding user to project with readAndWrite token"
|
"error adding user to project with readAndWrite token"
|
||||||
return next(err)
|
return next(err)
|
||||||
req.params.Project_id = project._id.toString()
|
return TokenAccessController._loadEditor(project._id, req, res, next)
|
||||||
return ProjectController.loadEditor(req, res, next)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
Project = require('../../models/Project').Project
|
Project = require('../../models/Project').Project
|
||||||
PublicAccessLevels = require '../Authorization/PublicAccessLevels'
|
PublicAccessLevels = require '../Authorization/PublicAccessLevels'
|
||||||
ObjectId = require("mongojs").ObjectId
|
ObjectId = require("mongojs").ObjectId
|
||||||
|
Settings = require('settings-sharelatex')
|
||||||
|
|
||||||
module.exports = TokenAccessHandler =
|
module.exports = TokenAccessHandler =
|
||||||
|
|
||||||
|
ANONYMOUS_READ_AND_WRITE_ENABLED:
|
||||||
|
Settings.allowAnonymousReadAndWriteSharing == true
|
||||||
|
|
||||||
findProjectWithReadOnlyToken: (token, callback=(err, project)->) ->
|
findProjectWithReadOnlyToken: (token, callback=(err, project)->) ->
|
||||||
Project.findOne {
|
Project.findOne {
|
||||||
'tokens.readOnly': token,
|
'tokens.readOnly': token,
|
||||||
|
@ -41,28 +45,30 @@ module.exports = TokenAccessHandler =
|
||||||
$addToSet: {tokenAccessReadAndWrite_refs: userId}
|
$addToSet: {tokenAccessReadAndWrite_refs: userId}
|
||||||
}, callback
|
}, callback
|
||||||
|
|
||||||
grantSessionReadOnlyTokenAccess: (req, projectId, token) ->
|
grantSessionTokenAccess: (req, projectId, token) ->
|
||||||
if req.session?
|
if req.session?
|
||||||
if !req.session.anonReadOnlyTokenAccess?
|
if !req.session.anonTokenAccess?
|
||||||
req.session.anonReadOnlyTokenAccess = {}
|
req.session.anonTokenAccess = {}
|
||||||
req.session.anonReadOnlyTokenAccess[projectId.toString()] = token.toString()
|
req.session.anonTokenAccess[projectId.toString()] = token.toString()
|
||||||
|
|
||||||
getRequestToken: (req, projectId) ->
|
getRequestToken: (req, projectId) ->
|
||||||
token = (
|
token = (
|
||||||
req?.session?.anonReadOnlyTokenAccess?[projectId.toString()] or
|
req?.session?.anonTokenAccess?[projectId.toString()] or
|
||||||
req?.headers['x-sl-anon-token']
|
req?.headers['x-sl-anon-token']
|
||||||
)
|
)
|
||||||
return token
|
return token
|
||||||
|
|
||||||
isValidReadOnlyToken: (projectId, token, callback=(err, allowed)->) ->
|
isValidToken: (projectId, token, callback=(err, isValidReadAndWrite, isValidReadOnly)->) ->
|
||||||
if !token
|
if !token
|
||||||
return callback null, false
|
return callback null, false, false
|
||||||
TokenAccessHandler.findProjectWithReadOnlyToken token, (err, project) ->
|
_validate = (project) ->
|
||||||
return callback(err) if err?
|
|
||||||
isAllowed = (
|
|
||||||
project? and
|
project? and
|
||||||
project.publicAccesLevel == PublicAccessLevels.TOKEN_BASED and
|
project.publicAccesLevel == PublicAccessLevels.TOKEN_BASED and
|
||||||
project._id.toString() == projectId.toString()
|
project._id.toString() == projectId.toString()
|
||||||
)
|
TokenAccessHandler.findProjectWithReadAndWriteToken token, (err, readAndWriteProject) ->
|
||||||
callback null, isAllowed
|
return callback(err) if err?
|
||||||
|
isValidReadAndWrite = _validate(readAndWriteProject)
|
||||||
|
TokenAccessHandler.findProjectWithReadOnlyToken token, (err, readOnlyProject) ->
|
||||||
|
return callback(err) if err?
|
||||||
|
isValidReadOnly = _validate(readOnlyProject)
|
||||||
|
callback null, isValidReadAndWrite, isValidReadOnly
|
||||||
|
|
|
@ -343,7 +343,6 @@ module.exports = class Router
|
||||||
TokenAccessController.readOnlyToken
|
TokenAccessController.readOnlyToken
|
||||||
|
|
||||||
webRouter.get '/:read_and_write_token([0-9]+[a-z]+)',
|
webRouter.get '/:read_and_write_token([0-9]+[a-z]+)',
|
||||||
AuthenticationController.requireLogin(),
|
|
||||||
TokenAccessController.readAndWriteToken
|
TokenAccessController.readAndWriteToken
|
||||||
|
|
||||||
webRouter.get '*', ErrorController.notFound
|
webRouter.get '*', ErrorController.notFound
|
||||||
|
|
|
@ -16,6 +16,11 @@ httpAuthUsers[httpAuthUser] = httpAuthPass
|
||||||
sessionSecret = "secret-please-change"
|
sessionSecret = "secret-please-change"
|
||||||
|
|
||||||
module.exports = settings =
|
module.exports = settings =
|
||||||
|
|
||||||
|
allowAnonymousReadAndWriteSharing:
|
||||||
|
process.env['SHARELATEX_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING'] == 'true'
|
||||||
|
|
||||||
|
|
||||||
# File storage
|
# File storage
|
||||||
# ------------
|
# ------------
|
||||||
#
|
#
|
||||||
|
|
|
@ -14,7 +14,7 @@ describe "AuthorizationManager", ->
|
||||||
"../../models/User": User: @User = {}
|
"../../models/User": User: @User = {}
|
||||||
"../Errors/Errors": Errors
|
"../Errors/Errors": Errors
|
||||||
"../TokenAccess/TokenAccessHandler": @TokenAccessHandler = {
|
"../TokenAccess/TokenAccessHandler": @TokenAccessHandler = {
|
||||||
isValidReadOnlyToken: sinon.stub().callsArgWith(2, null, false)
|
isValidToken: sinon.stub().callsArgWith(2, null, false, false)
|
||||||
}
|
}
|
||||||
@user_id = "user-id-1"
|
@user_id = "user-id-1"
|
||||||
@project_id = "project-id-1"
|
@project_id = "project-id-1"
|
||||||
|
|
|
@ -463,7 +463,7 @@ describe "TokenAccessController", ->
|
||||||
describe 'anonymous', ->
|
describe 'anonymous', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
|
@AuthenticationController.getLoggedInUserId = sinon.stub().returns(null)
|
||||||
@TokenAccessHandler.grantSessionReadOnlyTokenAccess = sinon.stub()
|
@TokenAccessHandler.grantSessionTokenAccess = sinon.stub()
|
||||||
|
|
||||||
describe 'when all goes well', ->
|
describe 'when all goes well', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
@ -486,9 +486,9 @@ describe "TokenAccessController", ->
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'should give the user session read-only access', (done) ->
|
it 'should give the user session read-only access', (done) ->
|
||||||
expect(@TokenAccessHandler.grantSessionReadOnlyTokenAccess.callCount)
|
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
|
||||||
.to.equal 1
|
.to.equal 1
|
||||||
expect(@TokenAccessHandler.grantSessionReadOnlyTokenAccess.calledWith(
|
expect(@TokenAccessHandler.grantSessionTokenAccess.calledWith(
|
||||||
@req, @projectId, @readOnlyToken
|
@req, @projectId, @readOnlyToken
|
||||||
))
|
))
|
||||||
.to.equal true
|
.to.equal true
|
||||||
|
@ -527,7 +527,7 @@ describe "TokenAccessController", ->
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'should not give the user session read-only access', (done) ->
|
it 'should not give the user session read-only access', (done) ->
|
||||||
expect(@TokenAccessHandler.grantSessionReadOnlyTokenAccess.callCount)
|
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
|
||||||
.to.equal 0
|
.to.equal 0
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
@ -567,7 +567,7 @@ describe "TokenAccessController", ->
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'should not give the user session read-only access', (done) ->
|
it 'should not give the user session read-only access', (done) ->
|
||||||
expect(@TokenAccessHandler.grantSessionReadOnlyTokenAccess.callCount)
|
expect(@TokenAccessHandler.grantSessionTokenAccess.callCount)
|
||||||
.to.equal 0
|
.to.equal 0
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ describe "TokenAccessHandler", ->
|
||||||
@req = {}
|
@req = {}
|
||||||
@TokenAccessHandler = SandboxedModule.require modulePath, requires:
|
@TokenAccessHandler = SandboxedModule.require modulePath, requires:
|
||||||
'../../models/Project': {Project: @Project = {}}
|
'../../models/Project': {Project: @Project = {}}
|
||||||
|
'settings-sharelatex': {}
|
||||||
|
|
||||||
|
|
||||||
describe 'findProjectWithReadOnlyToken', ->
|
describe 'findProjectWithReadOnlyToken', ->
|
||||||
|
@ -175,98 +176,187 @@ describe "TokenAccessHandler", ->
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
|
||||||
describe 'grantSessionReadOnlyTokenAccess', ->
|
describe 'grantSessionTokenAccess', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@req = {session: {}, headers: {}}
|
@req = {session: {}, headers: {}}
|
||||||
|
|
||||||
it 'should add the token to the session', (done) ->
|
it 'should add the token to the session', (done) ->
|
||||||
@TokenAccessHandler.grantSessionReadOnlyTokenAccess(@req, @projectId, @token)
|
@TokenAccessHandler.grantSessionTokenAccess(@req, @projectId, @token)
|
||||||
expect(@req.session.anonReadOnlyTokenAccess[@projectId.toString()])
|
expect(@req.session.anonTokenAccess[@projectId.toString()])
|
||||||
.to.equal @token
|
.to.equal @token
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
|
||||||
describe 'isValidReadOnlyToken', ->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
describe 'isValidToken', ->
|
||||||
|
|
||||||
|
describe 'when a read-only project is found', ->
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
||||||
|
.callsArgWith(1, null, null)
|
||||||
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
||||||
.callsArgWith(1, null, @project)
|
.callsArgWith(1, null, @project)
|
||||||
|
|
||||||
it 'should call findProjectWithReadOnlyToken', (done) ->
|
it 'should try to find projects with both kinds of token', (done) ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @projectId, @token, (err, allowed) =>
|
@TokenAccessHandler.isValidToken @projectId, @token, (err, allowed) =>
|
||||||
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
||||||
|
.to.equal 1
|
||||||
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
||||||
.to.equal 1
|
.to.equal 1
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'should allow access', (done) ->
|
it 'should allow read-only access', (done) ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @projectId, @token, (err, allowed) =>
|
@TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
|
||||||
expect(err).to.not.exist
|
expect(err).to.not.exist
|
||||||
expect(allowed).to.equal true
|
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()
|
done()
|
||||||
|
|
||||||
describe 'when no project is found', ->
|
describe 'when no project is found', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
||||||
|
.callsArgWith(1, null, null)
|
||||||
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
||||||
.callsArgWith(1, null, null)
|
.callsArgWith(1, null, null)
|
||||||
|
|
||||||
it 'should call findProjectWithReadOnlyToken', (done) ->
|
it 'should try to find projects with both kinds of token', (done) ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @projectId, @token, (err, allowed) =>
|
@TokenAccessHandler.isValidToken @projectId, @token, (err, allowed) =>
|
||||||
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
||||||
|
.to.equal 1
|
||||||
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
||||||
.to.equal 1
|
.to.equal 1
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'should not allow access', (done) ->
|
it 'should not allow any access', (done) ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @req, @projectId, (err, allowed) =>
|
@TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
|
||||||
expect(err).to.not.exist
|
expect(err).to.not.exist
|
||||||
expect(allowed).to.equal false
|
expect(rw).to.equal false
|
||||||
|
expect(ro).to.equal false
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe 'when no findProject produces an error', ->
|
describe 'when findProject produces an error', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
||||||
|
.callsArgWith(1, null, null)
|
||||||
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
||||||
.callsArgWith(1, new Error('woops'))
|
.callsArgWith(1, new Error('woops'))
|
||||||
|
|
||||||
it 'should call findProjectWithReadOnlyToken', (done) ->
|
it 'should try to find projects with both kinds of token', (done) ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @projectId, @token, (err, allowed) =>
|
@TokenAccessHandler.isValidToken @projectId, @token, (err, allowed) =>
|
||||||
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
||||||
|
.to.equal 1
|
||||||
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
||||||
.to.equal 1
|
.to.equal 1
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'should produce an error and not allow access', (done) ->
|
it 'should produce an error and not allow access', (done) ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @projectId, @token, (err, allowed) =>
|
@TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
|
||||||
expect(err).to.exist
|
expect(err).to.exist
|
||||||
expect(err).to.be.instanceof Error
|
expect(err).to.be.instanceof Error
|
||||||
expect(allowed).to.equal undefined
|
expect(rw).to.equal undefined
|
||||||
|
expect(ro).to.equal undefined
|
||||||
done()
|
done()
|
||||||
|
|
||||||
describe 'when project is not set to token-based access', ->
|
describe 'when project is not set to token-based access', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@project.publicAccesLevel = 'private'
|
@project.publicAccesLevel = 'private'
|
||||||
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
|
||||||
.callsArgWith(1, null, @project)
|
|
||||||
|
|
||||||
it 'should call findProjectWithReadOnlyToken', (done) ->
|
describe 'for read-and-write project', ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @projectId, @token, (err, allowed) =>
|
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)
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
||||||
.to.equal 1
|
.to.equal 1
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'should not allow access', (done) ->
|
it 'should not allow any access', (done) ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @projectId, @token, (err, allowed) =>
|
@TokenAccessHandler.isValidToken @projectId, @token, (err, rw, ro) =>
|
||||||
expect(err).to.not.exist
|
expect(err).to.not.exist
|
||||||
expect(allowed).to.equal false
|
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()
|
done()
|
||||||
|
|
||||||
describe 'with nothing', ->
|
describe 'with nothing', ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
|
@TokenAccessHandler.findProjectWithReadAndWriteToken = sinon.stub()
|
||||||
|
.callsArgWith(1, null, @project)
|
||||||
|
@TokenAccessHandler.findProjectWithReadOnlyToken = sinon.stub()
|
||||||
|
.callsArgWith(1, null, null)
|
||||||
|
|
||||||
it 'should not call findProjectWithReadOnlyToken', (done) ->
|
it 'should not call findProjectWithReadOnlyToken', (done) ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @projectId, null, (err, allowed) =>
|
@TokenAccessHandler.isValidToken @projectId, null, (err, allowed) =>
|
||||||
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
expect(@TokenAccessHandler.findProjectWithReadOnlyToken.callCount)
|
||||||
.to.equal 0
|
.to.equal 0
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'should not allow access', (done) ->
|
it 'should try to find projects with both kinds of token', (done) ->
|
||||||
@TokenAccessHandler.isValidReadOnlyToken @req, @projectId, (err, allowed) =>
|
@TokenAccessHandler.isValidToken @projectId, null, (err, allowed) =>
|
||||||
expect(err).to.not.exist
|
expect(@TokenAccessHandler.findProjectWithReadAndWriteToken.callCount)
|
||||||
expect(allowed).to.equal false
|
.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()
|
done()
|
||||||
|
|
|
@ -241,6 +241,57 @@ describe 'TokenAccess', ->
|
||||||
expect(body.privilegeLevel).to.equal false
|
expect(body.privilegeLevel).to.equal false
|
||||||
, done)
|
, done)
|
||||||
|
|
||||||
|
if !settings.allowAnonymousReadAndWriteSharing
|
||||||
|
console.log ">> Skipping anonymous read-write token tests"
|
||||||
|
else
|
||||||
|
describe 'anonymous read-and-write token', ->
|
||||||
|
before (done) ->
|
||||||
|
@owner.createProject 'token-anon-rw-test#{Math.random()}', (err, project_id) =>
|
||||||
|
return done(err) if err?
|
||||||
|
@project_id = project_id
|
||||||
|
@owner.makeTokenBased @project_id, (err) =>
|
||||||
|
return done(err) if err?
|
||||||
|
@owner.getProject @project_id, (err, project) =>
|
||||||
|
return done(err) if err?
|
||||||
|
@tokens = project.tokens
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should deny access before the token is used', (done) ->
|
||||||
|
try_read_access(@anon, @project_id, (response, body) =>
|
||||||
|
expect(response.statusCode).to.equal 302
|
||||||
|
expect(body).to.match /.*\/restricted.*/
|
||||||
|
, done)
|
||||||
|
|
||||||
|
it 'should allow the user to access project via read-and-write token url', (done) ->
|
||||||
|
try_read_and_write_token_access(@anon, @tokens.readAndWrite, (response, body) =>
|
||||||
|
expect(response.statusCode).to.equal 200
|
||||||
|
, done)
|
||||||
|
|
||||||
|
it 'should allow the user to anonymously join the project with read-and-write access', (done) ->
|
||||||
|
try_anon_content_access(@anon, @project_id, @tokens.readAndWrite, (response, body) =>
|
||||||
|
expect(body.privilegeLevel).to.equal 'readAndWrite'
|
||||||
|
, done)
|
||||||
|
|
||||||
|
describe 'made private again', ->
|
||||||
|
before (done) ->
|
||||||
|
@owner.makePrivate @project_id, () -> setTimeout(done, 1000)
|
||||||
|
|
||||||
|
it 'should deny access to project', (done) ->
|
||||||
|
try_read_access(@anon, @project_id, (response, body) =>
|
||||||
|
expect(response.statusCode).to.equal 302
|
||||||
|
expect(body).to.match /.*\/restricted.*/
|
||||||
|
, done)
|
||||||
|
|
||||||
|
it 'should not allow the user to access read-and-write token', (done) ->
|
||||||
|
try_read_and_write_token_access(@anon, @tokens.readAndWrite, (response, body) =>
|
||||||
|
expect(response.statusCode).to.equal 404
|
||||||
|
, done)
|
||||||
|
|
||||||
|
it 'should not allow the user to join the project', (done) ->
|
||||||
|
try_anon_content_access(@anon, @project_id, @tokens.readAndWrite, (response, body) =>
|
||||||
|
expect(body.privilegeLevel).to.equal false
|
||||||
|
, done)
|
||||||
|
|
||||||
|
|
||||||
describe 'private overleaf project', ->
|
describe 'private overleaf project', ->
|
||||||
before (done) ->
|
before (done) ->
|
||||||
|
|
Loading…
Reference in a new issue