mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-30 07:05:19 -05:00
Generate tokens on old projects if they're not present
This commit is contained in:
parent
b6c2a8f7f7
commit
6482cd7dd8
8 changed files with 242 additions and 31 deletions
|
@ -9,6 +9,7 @@ DocumentUpdaterHandler = require('../DocumentUpdater/DocumentUpdaterHandler')
|
||||||
EditorRealTimeController = require("./EditorRealTimeController")
|
EditorRealTimeController = require("./EditorRealTimeController")
|
||||||
async = require('async')
|
async = require('async')
|
||||||
LockManager = require("../../infrastructure/LockManager")
|
LockManager = require("../../infrastructure/LockManager")
|
||||||
|
PublicAccessLevels = require("../Authorization/PublicAccessLevels")
|
||||||
_ = require('underscore')
|
_ = require('underscore')
|
||||||
|
|
||||||
module.exports = EditorController =
|
module.exports = EditorController =
|
||||||
|
@ -200,8 +201,22 @@ module.exports = EditorController =
|
||||||
setPublicAccessLevel : (project_id, newAccessLevel, callback = (err) ->) ->
|
setPublicAccessLevel : (project_id, newAccessLevel, callback = (err) ->) ->
|
||||||
ProjectDetailsHandler.setPublicAccessLevel project_id, newAccessLevel, (err) ->
|
ProjectDetailsHandler.setPublicAccessLevel project_id, newAccessLevel, (err) ->
|
||||||
return callback(err) if err?
|
return callback(err) if err?
|
||||||
EditorRealTimeController.emitToRoom project_id, 'publicAccessLevelUpdated', newAccessLevel
|
EditorRealTimeController.emitToRoom(
|
||||||
callback()
|
project_id,
|
||||||
|
'project:publicAccessLevel:changed',
|
||||||
|
{newAccessLevel}
|
||||||
|
)
|
||||||
|
if newAccessLevel == PublicAccessLevels.TOKEN_BASED
|
||||||
|
ProjectDetailsHandler.ensureTokensArePresent project_id, (err, tokens) ->
|
||||||
|
return callback(err) if err?
|
||||||
|
EditorRealTimeController.emitToRoom(
|
||||||
|
project_id,
|
||||||
|
'project:tokens:changed',
|
||||||
|
{tokens}
|
||||||
|
)
|
||||||
|
callback()
|
||||||
|
else
|
||||||
|
callback()
|
||||||
|
|
||||||
setRootDoc: (project_id, newRootDocID, callback = (err) ->) ->
|
setRootDoc: (project_id, newRootDocID, callback = (err) ->) ->
|
||||||
ProjectEntityHandler.setRootDoc project_id, newRootDocID, (err) ->
|
ProjectEntityHandler.setRootDoc project_id, newRootDocID, (err) ->
|
||||||
|
|
|
@ -6,6 +6,7 @@ tpdsUpdateSender = require '../ThirdPartyDataStore/TpdsUpdateSender'
|
||||||
_ = require("underscore")
|
_ = require("underscore")
|
||||||
PublicAccessLevels = require("../Authorization/PublicAccessLevels")
|
PublicAccessLevels = require("../Authorization/PublicAccessLevels")
|
||||||
Errors = require("../Errors/Errors")
|
Errors = require("../Errors/Errors")
|
||||||
|
ProjectTokenGenerator = require('./ProjectTokenGenerator')
|
||||||
|
|
||||||
module.exports = ProjectDetailsHandler =
|
module.exports = ProjectDetailsHandler =
|
||||||
getDetails: (project_id, callback)->
|
getDetails: (project_id, callback)->
|
||||||
|
@ -65,6 +66,25 @@ module.exports = ProjectDetailsHandler =
|
||||||
setPublicAccessLevel : (project_id, newAccessLevel, callback = ->)->
|
setPublicAccessLevel : (project_id, newAccessLevel, callback = ->)->
|
||||||
logger.log project_id: project_id, level: newAccessLevel, "set public access level"
|
logger.log project_id: project_id, level: newAccessLevel, "set public access level"
|
||||||
# TODO: remove the read-only and read-and-write items from here
|
# TODO: remove the read-only and read-and-write items from here
|
||||||
if project_id? && newAccessLevel? and _.include [PublicAccessLevels.READ_ONLY, PublicAccessLevels.READ_AND_WRITE, PublicAccessLevels.PRIVATE, PublicAccessLevels.TOKEN_BASED], newAccessLevel
|
if project_id? && newAccessLevel? and _.include [
|
||||||
|
PublicAccessLevels.READ_ONLY,
|
||||||
|
PublicAccessLevels.READ_AND_WRITE,
|
||||||
|
PublicAccessLevels.PRIVATE,
|
||||||
|
PublicAccessLevels.TOKEN_BASED
|
||||||
|
], newAccessLevel
|
||||||
Project.update {_id:project_id},{publicAccesLevel:newAccessLevel}, (err)->
|
Project.update {_id:project_id},{publicAccesLevel:newAccessLevel}, (err)->
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
ensureTokensArePresent: (project_id, callback=(err, tokens)->) ->
|
||||||
|
ProjectGetter.getProject project_id, {tokens: 1}, (err, project) ->
|
||||||
|
return callback(err) if err?
|
||||||
|
if project.tokens? and project.tokens.readOnly? and project.tokens.readAndWrite?
|
||||||
|
return callback(null, project.tokens)
|
||||||
|
else
|
||||||
|
tokens =
|
||||||
|
readOnly: ProjectTokenGenerator.readOnlyToken()
|
||||||
|
readAndWrite: ProjectTokenGenerator.readAndWriteToken()
|
||||||
|
Project.update {_id: project_id}, {$set: {tokens: tokens}}, (err) ->
|
||||||
|
return callback(err) if err?
|
||||||
|
callback(null, tokens)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
module.exports = ProjectTokenGenerator =
|
||||||
|
|
||||||
|
|
||||||
|
readOnlyToken: () ->
|
||||||
|
length = 12
|
||||||
|
tokenAlpha = 'bcdfghjkmnpqrstvwxyz'
|
||||||
|
result = ''
|
||||||
|
for _n in [1..length]
|
||||||
|
i = Math.floor(Math.floor(Math.random() * tokenAlpha.length))
|
||||||
|
result += tokenAlpha[i]
|
||||||
|
return result
|
||||||
|
|
||||||
|
readAndWriteToken: () ->
|
||||||
|
numerics = Math.random().toString().slice(2, 12)
|
||||||
|
token = ProjectTokenGenerator.readOnlyToken()
|
||||||
|
return "#{numerics}#{token}"
|
|
@ -6,14 +6,7 @@ logger = require('logger-sharelatex')
|
||||||
sanitize = require('sanitizer')
|
sanitize = require('sanitizer')
|
||||||
concreteObjectId = require('mongoose').Types.ObjectId
|
concreteObjectId = require('mongoose').Types.ObjectId
|
||||||
Errors = require "../Features/Errors/Errors"
|
Errors = require "../Features/Errors/Errors"
|
||||||
|
ProjectTokenGenerator = require '../Features/Project/ProjectTokenGenerator'
|
||||||
generateToken = (length) ->
|
|
||||||
tokenAlpha = 'bcdfghjkmnpqrstvwxyz'
|
|
||||||
result = ''
|
|
||||||
for _n in [1..length]
|
|
||||||
i = Math.floor(Math.floor(Math.random() * tokenAlpha.length))
|
|
||||||
result += tokenAlpha[i]
|
|
||||||
return result
|
|
||||||
|
|
||||||
Schema = mongoose.Schema
|
Schema = mongoose.Schema
|
||||||
ObjectId = Schema.ObjectId
|
ObjectId = Schema.ObjectId
|
||||||
|
@ -43,13 +36,11 @@ ProjectSchema = new Schema
|
||||||
tokens :
|
tokens :
|
||||||
readOnly : {
|
readOnly : {
|
||||||
type: String,
|
type: String,
|
||||||
default: generateToken(14),
|
default: ProjectTokenGenerator.readOnlyToken()
|
||||||
index: {unique: true}
|
|
||||||
}
|
}
|
||||||
readAndWrite : {
|
readAndWrite : {
|
||||||
type: String,
|
type: String,
|
||||||
default: Math.random().toString().slice(2, 10) + generateToken(12)
|
default: ProjectTokenGenerator.readAndWriteToken()
|
||||||
index: {unique: true}
|
|
||||||
}
|
}
|
||||||
tokenAccessReadOnly_refs : [ type:ObjectId, ref:'User' ]
|
tokenAccessReadOnly_refs : [ type:ObjectId, ref:'User' ]
|
||||||
tokenAccessReadAndWrite_refs : [ type:ObjectId, ref:'User' ]
|
tokenAccessReadAndWrite_refs : [ type:ObjectId, ref:'User' ]
|
||||||
|
|
|
@ -12,6 +12,16 @@ define [
|
||||||
scope: $scope
|
scope: $scope
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ide.socket.on 'project:tokens:changed', (data) =>
|
||||||
|
if data.tokens?
|
||||||
|
ide.$scope.project.tokens = data.tokens
|
||||||
|
$scope.$digest()
|
||||||
|
|
||||||
|
ide.socket.on 'project:publicAccessLevel:changed', (data) =>
|
||||||
|
if data.newAccessLevel?
|
||||||
|
ide.$scope.project.publicAccesLevel = data.newAccessLevel
|
||||||
|
$scope.$digest()
|
||||||
|
|
||||||
ide.socket.on 'project:membership:changed', (data) =>
|
ide.socket.on 'project:membership:changed', (data) =>
|
||||||
if data.members
|
if data.members
|
||||||
projectMembers.getMembers()
|
projectMembers.getMembers()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
define [
|
define [
|
||||||
"base"
|
"base"
|
||||||
], (App) ->
|
], (App) ->
|
||||||
App.controller "ShareProjectModalController", ($scope, $modalInstance, $timeout, projectMembers, projectInvites, $modal, $http) ->
|
App.controller "ShareProjectModalController", ($scope, $modalInstance, $timeout, projectMembers, projectInvites, $modal, $http, ide) ->
|
||||||
$scope.inputs = {
|
$scope.inputs = {
|
||||||
privileges: "readAndWrite"
|
privileges: "readAndWrite"
|
||||||
contacts: []
|
contacts: []
|
||||||
|
@ -200,10 +200,16 @@ define [
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.getReadAndWriteTokenLink = () ->
|
$scope.getReadAndWriteTokenLink = () ->
|
||||||
location.origin + "/" + $scope.project.tokens.readAndWrite
|
if $scope?.project?.tokens?.readAndWrite?
|
||||||
|
location.origin + "/" + $scope.project.tokens.readAndWrite
|
||||||
|
else
|
||||||
|
''
|
||||||
|
|
||||||
$scope.getReadOnlyTokenLink = () ->
|
$scope.getReadOnlyTokenLink = () ->
|
||||||
location.origin + "/read/" + $scope.project.tokens.readOnly
|
if $scope?.project?.tokens?.readOnly?
|
||||||
|
location.origin + "/read/" + $scope.project.tokens.readOnly
|
||||||
|
else
|
||||||
|
''
|
||||||
|
|
||||||
$scope.done = () ->
|
$scope.done = () ->
|
||||||
$modalInstance.close()
|
$modalInstance.close()
|
||||||
|
|
|
@ -564,20 +564,99 @@ describe "EditorController", ->
|
||||||
|
|
||||||
describe "setPublicAccessLevel", ->
|
describe "setPublicAccessLevel", ->
|
||||||
|
|
||||||
beforeEach ->
|
describe 'when setting to private', ->
|
||||||
@newAccessLevel = "public"
|
beforeEach ->
|
||||||
@ProjectDetailsHandler.setPublicAccessLevel = sinon.stub().callsArgWith(2, null)
|
@newAccessLevel = 'private'
|
||||||
@EditorRealTimeController.emitToRoom = sinon.stub()
|
@ProjectDetailsHandler.setPublicAccessLevel = sinon.stub().callsArgWith(2, null)
|
||||||
|
@ProjectDetailsHandler.ensureTokensArePresent = sinon.stub()
|
||||||
|
.callsArgWith(1, null, @tokens)
|
||||||
|
@EditorRealTimeController.emitToRoom = sinon.stub()
|
||||||
|
|
||||||
it "should call the EditorController", (done)->
|
it 'should set the access level', (done) ->
|
||||||
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
@ProjectDetailsHandler.setPublicAccessLevel.calledWith(@project_id, @newAccessLevel).should.equal true
|
@ProjectDetailsHandler.setPublicAccessLevel
|
||||||
done()
|
.calledWith(@project_id, @newAccessLevel).should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
it "should emit the update to the room", (done)->
|
it 'should broadcast the access level change', (done) ->
|
||||||
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
@EditorRealTimeController.emitToRoom.calledWith(@project_id, 'publicAccessLevelUpdated', @newAccessLevel).should.equal true
|
@EditorRealTimeController.emitToRoom
|
||||||
done()
|
.calledWith(@project_id, 'project:publicAccessLevel:changed').should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should not ensure tokens are present for project', (done) ->
|
||||||
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
|
@ProjectDetailsHandler.ensureTokensArePresent
|
||||||
|
.calledWith(@project_id).should.equal false
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should not broadcast a token change', (done) ->
|
||||||
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
|
@EditorRealTimeController.emitToRoom
|
||||||
|
.calledWith(@project_id, 'project:tokens:changed', {tokens: @tokens})
|
||||||
|
.should.equal false
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should not produce an error', (done) ->
|
||||||
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, (err) =>
|
||||||
|
expect(err).to.not.exist
|
||||||
|
done()
|
||||||
|
|
||||||
|
describe 'when setting to tokenBased', ->
|
||||||
|
beforeEach ->
|
||||||
|
@newAccessLevel = 'tokenBased'
|
||||||
|
@tokens = {readOnly: 'aaa', readAndWrite: '42bbb'}
|
||||||
|
@ProjectDetailsHandler.setPublicAccessLevel = sinon.stub()
|
||||||
|
.callsArgWith(2, null)
|
||||||
|
@ProjectDetailsHandler.ensureTokensArePresent = sinon.stub()
|
||||||
|
.callsArgWith(1, null, @tokens)
|
||||||
|
@EditorRealTimeController.emitToRoom = sinon.stub()
|
||||||
|
|
||||||
|
it 'should set the access level', (done) ->
|
||||||
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
|
@ProjectDetailsHandler.setPublicAccessLevel
|
||||||
|
.calledWith(@project_id, @newAccessLevel).should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should broadcast the access level change', (done) ->
|
||||||
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
|
@EditorRealTimeController.emitToRoom
|
||||||
|
.calledWith(@project_id, 'project:publicAccessLevel:changed')
|
||||||
|
.should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should ensure tokens are present for project', (done) ->
|
||||||
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
|
@ProjectDetailsHandler.ensureTokensArePresent
|
||||||
|
.calledWith(@project_id).should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should broadcast the token change too', (done) ->
|
||||||
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
|
@EditorRealTimeController.emitToRoom
|
||||||
|
.calledWith(@project_id, 'project:tokens:changed', {tokens: @tokens})
|
||||||
|
.should.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should not produce an error', (done) ->
|
||||||
|
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, (err) =>
|
||||||
|
expect(err).to.not.exist
|
||||||
|
done()
|
||||||
|
|
||||||
|
# beforeEach ->
|
||||||
|
# @newAccessLevel = "public"
|
||||||
|
# @ProjectDetailsHandler.setPublicAccessLevel = sinon.stub().callsArgWith(2, null)
|
||||||
|
# @EditorRealTimeController.emitToRoom = sinon.stub()
|
||||||
|
|
||||||
|
# it "should call the EditorController", (done)->
|
||||||
|
# @EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
|
# @ProjectDetailsHandler.setPublicAccessLevel.calledWith(@project_id, @newAccessLevel).should.equal true
|
||||||
|
# done()
|
||||||
|
|
||||||
|
# it "should emit the update to the room", (done)->
|
||||||
|
# @EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||||
|
# @EditorRealTimeController.emitToRoom.calledWith(@project_id, 'publicAccessLevelUpdated', @newAccessLevel).should.equal true
|
||||||
|
# done()
|
||||||
|
|
||||||
describe "setRootDoc", ->
|
describe "setRootDoc", ->
|
||||||
|
|
||||||
|
@ -594,4 +673,4 @@ describe "EditorController", ->
|
||||||
it "should emit the update to the room", (done)->
|
it "should emit the update to the room", (done)->
|
||||||
@EditorController.setRootDoc @project_id, @newRootDocID, =>
|
@EditorController.setRootDoc @project_id, @newRootDocID, =>
|
||||||
@EditorRealTimeController.emitToRoom.calledWith(@project_id, 'rootDocUpdated', @newRootDocID).should.equal true
|
@EditorRealTimeController.emitToRoom.calledWith(@project_id, 'rootDocUpdated', @newRootDocID).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
|
@ -38,6 +38,7 @@ describe 'ProjectDetailsHandler', ->
|
||||||
'logger-sharelatex':
|
'logger-sharelatex':
|
||||||
log:->
|
log:->
|
||||||
err:->
|
err:->
|
||||||
|
'./ProjectTokenGenerator': @ProjectTokenGenerator = {}
|
||||||
|
|
||||||
describe "getDetails", ->
|
describe "getDetails", ->
|
||||||
|
|
||||||
|
@ -149,3 +150,76 @@ describe 'ProjectDetailsHandler', ->
|
||||||
@ProjectModel.update.calledWith({_id: @project_id}, {publicAccesLevel: @accessLevel}).should.equal true
|
@ProjectModel.update.calledWith({_id: @project_id}, {publicAccesLevel: @accessLevel}).should.equal true
|
||||||
done()
|
done()
|
||||||
|
|
||||||
|
describe "ensureTokensArePresent", ->
|
||||||
|
beforeEach ->
|
||||||
|
|
||||||
|
describe 'when the project has tokens', ->
|
||||||
|
beforeEach ->
|
||||||
|
@project =
|
||||||
|
_id: @project_id
|
||||||
|
tokens:
|
||||||
|
readOnly: 'aaa'
|
||||||
|
readAndWrite: '42bbb'
|
||||||
|
@ProjectGetter.getProject = sinon.stub()
|
||||||
|
.callsArgWith(2, null, @project)
|
||||||
|
@ProjectModel.update = sinon.stub()
|
||||||
|
|
||||||
|
it 'should get the project', (done) ->
|
||||||
|
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
|
||||||
|
expect(@ProjectGetter.getProject.callCount).to.equal 1
|
||||||
|
expect(@ProjectGetter.getProject.calledWith(@project_id, {tokens: 1}))
|
||||||
|
.to.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should not update the project with new tokens', (done) ->
|
||||||
|
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
|
||||||
|
expect(@ProjectModel.update.callCount).to.equal 0
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should produce the tokens without error', (done) ->
|
||||||
|
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
|
||||||
|
expect(err).to.not.exist
|
||||||
|
expect(tokens).to.deep.equal @project.tokens
|
||||||
|
done()
|
||||||
|
|
||||||
|
describe 'when tokens are missing', ->
|
||||||
|
beforeEach ->
|
||||||
|
@project =
|
||||||
|
_id: @project_id
|
||||||
|
@ProjectGetter.getProject = sinon.stub()
|
||||||
|
.callsArgWith(2, null, @project)
|
||||||
|
@readOnlyToken = 'abc'
|
||||||
|
@readAndWriteToken = '42def'
|
||||||
|
@ProjectTokenGenerator.readOnlyToken = sinon.stub().returns(@readOnlyToken)
|
||||||
|
@ProjectTokenGenerator.readAndWriteToken = sinon.stub().returns(@readAndWriteToken)
|
||||||
|
@ProjectModel.update = sinon.stub()
|
||||||
|
.callsArgWith(2, null)
|
||||||
|
|
||||||
|
it 'should get the project', (done) ->
|
||||||
|
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
|
||||||
|
expect(@ProjectGetter.getProject.callCount).to.equal 1
|
||||||
|
expect(@ProjectGetter.getProject.calledWith(@project_id, {tokens: 1}))
|
||||||
|
.to.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should update the project with new tokens', (done) ->
|
||||||
|
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
|
||||||
|
expect(@ProjectTokenGenerator.readOnlyToken.callCount)
|
||||||
|
.to.equal 1
|
||||||
|
expect(@ProjectTokenGenerator.readAndWriteToken.callCount)
|
||||||
|
.to.equal 1
|
||||||
|
expect(@ProjectModel.update.callCount).to.equal 1
|
||||||
|
expect(@ProjectModel.update.calledWith(
|
||||||
|
{_id: @project_id},
|
||||||
|
{$set: {tokens: {readOnly: @readOnlyToken, readAndWrite: @readAndWriteToken}}}
|
||||||
|
)).to.equal true
|
||||||
|
done()
|
||||||
|
|
||||||
|
it 'should produce the tokens without error', (done) ->
|
||||||
|
@handler.ensureTokensArePresent @project_id, (err, tokens) =>
|
||||||
|
expect(err).to.not.exist
|
||||||
|
expect(tokens).to.deep.equal {
|
||||||
|
readOnly: @readOnlyToken,
|
||||||
|
readAndWrite: @readAndWriteToken
|
||||||
|
}
|
||||||
|
done()
|
||||||
|
|
Loading…
Reference in a new issue