mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -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")
|
||||
async = require('async')
|
||||
LockManager = require("../../infrastructure/LockManager")
|
||||
PublicAccessLevels = require("../Authorization/PublicAccessLevels")
|
||||
_ = require('underscore')
|
||||
|
||||
module.exports = EditorController =
|
||||
|
@ -200,8 +201,22 @@ module.exports = EditorController =
|
|||
setPublicAccessLevel : (project_id, newAccessLevel, callback = (err) ->) ->
|
||||
ProjectDetailsHandler.setPublicAccessLevel project_id, newAccessLevel, (err) ->
|
||||
return callback(err) if err?
|
||||
EditorRealTimeController.emitToRoom project_id, 'publicAccessLevelUpdated', newAccessLevel
|
||||
callback()
|
||||
EditorRealTimeController.emitToRoom(
|
||||
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) ->) ->
|
||||
ProjectEntityHandler.setRootDoc project_id, newRootDocID, (err) ->
|
||||
|
|
|
@ -6,6 +6,7 @@ tpdsUpdateSender = require '../ThirdPartyDataStore/TpdsUpdateSender'
|
|||
_ = require("underscore")
|
||||
PublicAccessLevels = require("../Authorization/PublicAccessLevels")
|
||||
Errors = require("../Errors/Errors")
|
||||
ProjectTokenGenerator = require('./ProjectTokenGenerator')
|
||||
|
||||
module.exports = ProjectDetailsHandler =
|
||||
getDetails: (project_id, callback)->
|
||||
|
@ -65,6 +66,25 @@ module.exports = ProjectDetailsHandler =
|
|||
setPublicAccessLevel : (project_id, newAccessLevel, callback = ->)->
|
||||
logger.log project_id: project_id, level: newAccessLevel, "set public access level"
|
||||
# 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)->
|
||||
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')
|
||||
concreteObjectId = require('mongoose').Types.ObjectId
|
||||
Errors = require "../Features/Errors/Errors"
|
||||
|
||||
generateToken = (length) ->
|
||||
tokenAlpha = 'bcdfghjkmnpqrstvwxyz'
|
||||
result = ''
|
||||
for _n in [1..length]
|
||||
i = Math.floor(Math.floor(Math.random() * tokenAlpha.length))
|
||||
result += tokenAlpha[i]
|
||||
return result
|
||||
ProjectTokenGenerator = require '../Features/Project/ProjectTokenGenerator'
|
||||
|
||||
Schema = mongoose.Schema
|
||||
ObjectId = Schema.ObjectId
|
||||
|
@ -43,13 +36,11 @@ ProjectSchema = new Schema
|
|||
tokens :
|
||||
readOnly : {
|
||||
type: String,
|
||||
default: generateToken(14),
|
||||
index: {unique: true}
|
||||
default: ProjectTokenGenerator.readOnlyToken()
|
||||
}
|
||||
readAndWrite : {
|
||||
type: String,
|
||||
default: Math.random().toString().slice(2, 10) + generateToken(12)
|
||||
index: {unique: true}
|
||||
default: ProjectTokenGenerator.readAndWriteToken()
|
||||
}
|
||||
tokenAccessReadOnly_refs : [ type:ObjectId, ref:'User' ]
|
||||
tokenAccessReadAndWrite_refs : [ type:ObjectId, ref:'User' ]
|
||||
|
|
|
@ -12,6 +12,16 @@ define [
|
|||
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) =>
|
||||
if data.members
|
||||
projectMembers.getMembers()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
define [
|
||||
"base"
|
||||
], (App) ->
|
||||
App.controller "ShareProjectModalController", ($scope, $modalInstance, $timeout, projectMembers, projectInvites, $modal, $http) ->
|
||||
App.controller "ShareProjectModalController", ($scope, $modalInstance, $timeout, projectMembers, projectInvites, $modal, $http, ide) ->
|
||||
$scope.inputs = {
|
||||
privileges: "readAndWrite"
|
||||
contacts: []
|
||||
|
@ -200,10 +200,16 @@ define [
|
|||
}
|
||||
|
||||
$scope.getReadAndWriteTokenLink = () ->
|
||||
location.origin + "/" + $scope.project.tokens.readAndWrite
|
||||
if $scope?.project?.tokens?.readAndWrite?
|
||||
location.origin + "/" + $scope.project.tokens.readAndWrite
|
||||
else
|
||||
''
|
||||
|
||||
$scope.getReadOnlyTokenLink = () ->
|
||||
location.origin + "/read/" + $scope.project.tokens.readOnly
|
||||
if $scope?.project?.tokens?.readOnly?
|
||||
location.origin + "/read/" + $scope.project.tokens.readOnly
|
||||
else
|
||||
''
|
||||
|
||||
$scope.done = () ->
|
||||
$modalInstance.close()
|
||||
|
|
|
@ -564,20 +564,99 @@ describe "EditorController", ->
|
|||
|
||||
describe "setPublicAccessLevel", ->
|
||||
|
||||
beforeEach ->
|
||||
@newAccessLevel = "public"
|
||||
@ProjectDetailsHandler.setPublicAccessLevel = sinon.stub().callsArgWith(2, null)
|
||||
@EditorRealTimeController.emitToRoom = sinon.stub()
|
||||
describe 'when setting to private', ->
|
||||
beforeEach ->
|
||||
@newAccessLevel = 'private'
|
||||
@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)->
|
||||
@EditorController.setPublicAccessLevel @project_id, @newAccessLevel, =>
|
||||
@ProjectDetailsHandler.setPublicAccessLevel.calledWith(@project_id, @newAccessLevel).should.equal true
|
||||
done()
|
||||
it 'should set the access level', (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()
|
||||
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 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", ->
|
||||
|
||||
|
@ -594,4 +673,4 @@ describe "EditorController", ->
|
|||
it "should emit the update to the room", (done)->
|
||||
@EditorController.setRootDoc @project_id, @newRootDocID, =>
|
||||
@EditorRealTimeController.emitToRoom.calledWith(@project_id, 'rootDocUpdated', @newRootDocID).should.equal true
|
||||
done()
|
||||
done()
|
||||
|
|
|
@ -38,6 +38,7 @@ describe 'ProjectDetailsHandler', ->
|
|||
'logger-sharelatex':
|
||||
log:->
|
||||
err:->
|
||||
'./ProjectTokenGenerator': @ProjectTokenGenerator = {}
|
||||
|
||||
describe "getDetails", ->
|
||||
|
||||
|
@ -149,3 +150,76 @@ describe 'ProjectDetailsHandler', ->
|
|||
@ProjectModel.update.calledWith({_id: @project_id}, {publicAccesLevel: @accessLevel}).should.equal true
|
||||
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