mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #160 from overleaf/jpa-backport-113
[backport] 113 and 126: ol_context
This commit is contained in:
commit
2cf7392192
10 changed files with 120 additions and 188 deletions
|
@ -6,13 +6,10 @@ module.exports = AuthorizationManager =
|
|||
AuthorizationManager._assertClientHasPrivilegeLevel client, ["readAndWrite", "owner"], callback
|
||||
|
||||
_assertClientHasPrivilegeLevel: (client, allowedLevels, callback = (error) ->) ->
|
||||
client.get "privilege_level", (error, privilegeLevel) ->
|
||||
return callback(error) if error?
|
||||
allowed = (privilegeLevel in allowedLevels)
|
||||
if allowed
|
||||
callback null
|
||||
else
|
||||
callback new Error("not authorized")
|
||||
if client.ol_context["privilege_level"] in allowedLevels
|
||||
callback null
|
||||
else
|
||||
callback new Error("not authorized")
|
||||
|
||||
assertClientCanViewProjectAndDoc: (client, doc_id, callback = (error) ->) ->
|
||||
AuthorizationManager.assertClientCanViewProject client, (error) ->
|
||||
|
@ -25,15 +22,15 @@ module.exports = AuthorizationManager =
|
|||
AuthorizationManager._assertClientCanAccessDoc client, doc_id, callback
|
||||
|
||||
_assertClientCanAccessDoc: (client, doc_id, callback = (error) ->) ->
|
||||
client.get "doc:#{doc_id}", (error, status) ->
|
||||
return callback(error) if error?
|
||||
if status? and status is "allowed"
|
||||
callback null
|
||||
else
|
||||
callback new Error("not authorized")
|
||||
if client.ol_context["doc:#{doc_id}"] is "allowed"
|
||||
callback null
|
||||
else
|
||||
callback new Error("not authorized")
|
||||
|
||||
addAccessToDoc: (client, doc_id, callback = (error) ->) ->
|
||||
client.set("doc:#{doc_id}", "allowed", callback)
|
||||
client.ol_context["doc:#{doc_id}"] = "allowed"
|
||||
callback(null)
|
||||
|
||||
removeAccessToDoc: (client, doc_id, callback = (error) ->) ->
|
||||
client.del("doc:#{doc_id}", callback)
|
||||
delete client.ol_context["doc:#{doc_id}"]
|
||||
callback(null)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
Utils = require "./Utils"
|
||||
async = require "async"
|
||||
|
||||
module.exports = HttpController =
|
||||
|
@ -8,11 +7,8 @@ module.exports = HttpController =
|
|||
# and for checking internal state in acceptance tests. The acceptances tests
|
||||
# should provide appropriate coverage.
|
||||
_getConnectedClientView: (ioClient, callback = (error, client) ->) ->
|
||||
client_id = ioClient.id
|
||||
Utils.getClientAttributes ioClient, [
|
||||
"project_id", "user_id", "first_name", "last_name", "email", "connected_time"
|
||||
], (error, {project_id, user_id, first_name, last_name, email, connected_time}) ->
|
||||
return callback(error) if error?
|
||||
client_id = ioClient.id
|
||||
{project_id, user_id, first_name, last_name, email, connected_time} = ioClient.ol_context
|
||||
client = {client_id, project_id, user_id, first_name, last_name, email, connected_time}
|
||||
client.rooms = []
|
||||
for name, joined of ioClient.manager.roomClients[client_id]
|
||||
|
|
|
@ -4,7 +4,6 @@ settings = require "settings-sharelatex"
|
|||
WebsocketController = require "./WebsocketController"
|
||||
HttpController = require "./HttpController"
|
||||
HttpApiController = require "./HttpApiController"
|
||||
Utils = require "./Utils"
|
||||
bodyParser = require "body-parser"
|
||||
base64id = require("base64id")
|
||||
|
||||
|
@ -16,10 +15,9 @@ httpAuth = basicAuth (user, pass)->
|
|||
return isValid
|
||||
|
||||
module.exports = Router =
|
||||
_handleError: (callback = ((error) ->), error, client, method, extraAttrs = {}) ->
|
||||
Utils.getClientAttributes client, ["project_id", "doc_id", "user_id"], (_, attrs) ->
|
||||
for key, value of extraAttrs
|
||||
attrs[key] = value
|
||||
_handleError: (callback = ((error) ->), error, client, method, attrs = {}) ->
|
||||
for key in ["project_id", "doc_id", "user_id"]
|
||||
attrs[key] = client.ol_context[key]
|
||||
attrs.client_id = client.id
|
||||
attrs.err = error
|
||||
if error.name == "CodedError"
|
||||
|
@ -57,6 +55,10 @@ module.exports = Router =
|
|||
app.post "/client/:client_id/disconnect", httpAuth, HttpApiController.disconnectClient
|
||||
|
||||
session.on 'connection', (error, client, session) ->
|
||||
# init client context, we may access it in Router._handleError before
|
||||
# setting any values
|
||||
client.ol_context = {}
|
||||
|
||||
client?.on "error", (err) ->
|
||||
logger.err { clientErr: err }, "socket.io client error"
|
||||
if client.connected
|
||||
|
@ -112,9 +114,10 @@ module.exports = Router =
|
|||
client.on "disconnect", () ->
|
||||
metrics.inc('socket-io.disconnect')
|
||||
metrics.gauge('socket-io.clients', io.sockets.clients()?.length - 1)
|
||||
|
||||
WebsocketController.leaveProject io, client, (err) ->
|
||||
if err?
|
||||
Router._handleError null, err, client, "leaveProject"
|
||||
Router._handleError (() ->), err, client, "leaveProject"
|
||||
|
||||
# Variadic. The possible arguments:
|
||||
# doc_id, callback
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
async = require "async"
|
||||
|
||||
module.exports = Utils =
|
||||
getClientAttributes: (client, keys, callback = (error, attributes) ->) ->
|
||||
attributes = {}
|
||||
jobs = keys.map (key) ->
|
||||
(callback) ->
|
||||
client.get key, (error, value) ->
|
||||
return callback(error) if error?
|
||||
attributes[key] = value
|
||||
callback()
|
||||
async.series jobs, (error) ->
|
||||
return callback(error) if error?
|
||||
callback null, attributes
|
|
@ -7,7 +7,6 @@ DocumentUpdaterManager = require "./DocumentUpdaterManager"
|
|||
ConnectedUsersManager = require "./ConnectedUsersManager"
|
||||
WebsocketLoadBalancer = require "./WebsocketLoadBalancer"
|
||||
RoomManager = require "./RoomManager"
|
||||
Utils = require "./Utils"
|
||||
|
||||
module.exports = WebsocketController =
|
||||
# If the protocol version changes when the client reconnects,
|
||||
|
@ -34,17 +33,18 @@ module.exports = WebsocketController =
|
|||
logger.warn {err, project_id, user_id, client_id: client.id}, "user is not authorized to join project"
|
||||
return callback(err)
|
||||
|
||||
client.set("privilege_level", privilegeLevel)
|
||||
client.set("user_id", user_id)
|
||||
client.set("project_id", project_id)
|
||||
client.set("owner_id", project?.owner?._id)
|
||||
client.set("first_name", user?.first_name)
|
||||
client.set("last_name", user?.last_name)
|
||||
client.set("email", user?.email)
|
||||
client.set("connected_time", new Date())
|
||||
client.set("signup_date", user?.signUpDate)
|
||||
client.set("login_count", user?.loginCount)
|
||||
client.set("is_restricted_user", !!(isRestrictedUser))
|
||||
client.ol_context = {}
|
||||
client.ol_context["privilege_level"] = privilegeLevel
|
||||
client.ol_context["user_id"] = user_id
|
||||
client.ol_context["project_id"] = project_id
|
||||
client.ol_context["owner_id"] = project?.owner?._id
|
||||
client.ol_context["first_name"] = user?.first_name
|
||||
client.ol_context["last_name"] = user?.last_name
|
||||
client.ol_context["email"] = user?.email
|
||||
client.ol_context["connected_time"] = new Date()
|
||||
client.ol_context["signup_date"] = user?.signUpDate
|
||||
client.ol_context["login_count"] = user?.loginCount
|
||||
client.ol_context["is_restricted_user"] = !!(isRestrictedUser)
|
||||
|
||||
RoomManager.joinProject client, project_id, (err) ->
|
||||
return callback(err) if err
|
||||
|
@ -59,8 +59,7 @@ module.exports = WebsocketController =
|
|||
# is determined by FLUSH_IF_EMPTY_DELAY.
|
||||
FLUSH_IF_EMPTY_DELAY: 500 #ms
|
||||
leaveProject: (io, client, callback = (error) ->) ->
|
||||
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
|
||||
return callback(error) if error?
|
||||
{project_id, user_id} = client.ol_context
|
||||
return callback() unless project_id # client did not join project
|
||||
|
||||
metrics.inc "editor.leave-project"
|
||||
|
@ -84,13 +83,12 @@ module.exports = WebsocketController =
|
|||
, WebsocketController.FLUSH_IF_EMPTY_DELAY
|
||||
|
||||
joinDoc: (client, doc_id, fromVersion = -1, options, callback = (error, doclines, version, ops, ranges) ->) ->
|
||||
if client.disconnected
|
||||
if client.disconnected
|
||||
metrics.inc('editor.join-doc.disconnected', 1, {status: 'immediately'})
|
||||
return callback()
|
||||
|
||||
metrics.inc "editor.join-doc"
|
||||
Utils.getClientAttributes client, ["project_id", "user_id", "is_restricted_user"], (error, {project_id, user_id, is_restricted_user}) ->
|
||||
return callback(error) if error?
|
||||
metrics.inc "editor.join-doc"
|
||||
{project_id, user_id, is_restricted_user} = client.ol_context
|
||||
return callback(new Error("no project_id found on client")) if !project_id?
|
||||
logger.log {user_id, project_id, doc_id, fromVersion, client_id: client.id}, "client joining doc"
|
||||
|
||||
|
@ -142,9 +140,9 @@ module.exports = WebsocketController =
|
|||
callback null, escapedLines, version, ops, ranges
|
||||
|
||||
leaveDoc: (client, doc_id, callback = (error) ->) ->
|
||||
# client may have disconnected, but we have to cleanup internal state.
|
||||
metrics.inc "editor.leave-doc"
|
||||
Utils.getClientAttributes client, ["project_id", "user_id"], (error, {project_id, user_id}) ->
|
||||
# client may have disconnected, but we have to cleanup internal state.
|
||||
metrics.inc "editor.leave-doc"
|
||||
{project_id, user_id} = client.ol_context
|
||||
logger.log {user_id, project_id, doc_id, client_id: client.id}, "client leaving doc"
|
||||
RoomManager.leaveDoc(client, doc_id)
|
||||
# we could remove permission when user leaves a doc, but because
|
||||
|
@ -153,15 +151,12 @@ module.exports = WebsocketController =
|
|||
## AuthorizationManager.removeAccessToDoc client, doc_id
|
||||
callback()
|
||||
updateClientPosition: (client, cursorData, callback = (error) ->) ->
|
||||
if client.disconnected
|
||||
if client.disconnected
|
||||
# do not create a ghost entry in redis
|
||||
return callback()
|
||||
|
||||
metrics.inc "editor.update-client-position", 0.1
|
||||
Utils.getClientAttributes client, [
|
||||
"project_id", "first_name", "last_name", "email", "user_id"
|
||||
], (error, {project_id, first_name, last_name, email, user_id}) ->
|
||||
return callback(error) if error?
|
||||
metrics.inc "editor.update-client-position", 0.1
|
||||
{project_id, first_name, last_name, email, user_id} = client.ol_context
|
||||
logger.log {user_id, project_id, client_id: client.id, cursorData: cursorData}, "updating client position"
|
||||
|
||||
AuthorizationManager.assertClientCanViewProjectAndDoc client, cursorData.doc_id, (error) ->
|
||||
|
@ -198,14 +193,12 @@ module.exports = WebsocketController =
|
|||
|
||||
CLIENT_REFRESH_DELAY: 1000
|
||||
getConnectedUsers: (client, callback = (error, users) ->) ->
|
||||
if client.disconnected
|
||||
if client.disconnected
|
||||
# they are not interested anymore, skip the redis lookups
|
||||
return callback()
|
||||
|
||||
metrics.inc "editor.get-connected-users"
|
||||
Utils.getClientAttributes client, ["project_id", "user_id", "is_restricted_user"], (error, clientAttributes) ->
|
||||
return callback(error) if error?
|
||||
{project_id, user_id, is_restricted_user} = clientAttributes
|
||||
metrics.inc "editor.get-connected-users"
|
||||
{project_id, user_id, is_restricted_user} = client.ol_context
|
||||
if is_restricted_user
|
||||
return callback(null, [])
|
||||
return callback(new Error("no project_id found on client")) if !project_id?
|
||||
|
@ -221,9 +214,8 @@ module.exports = WebsocketController =
|
|||
, WebsocketController.CLIENT_REFRESH_DELAY
|
||||
|
||||
applyOtUpdate: (client, doc_id, update, callback = (error) ->) ->
|
||||
# client may have disconnected, but we can submit their update to doc-updater anyways.
|
||||
Utils.getClientAttributes client, ["user_id", "project_id"], (error, {user_id, project_id}) ->
|
||||
return callback(error) if error?
|
||||
# client may have disconnected, but we can submit their update to doc-updater anyways.
|
||||
{user_id, project_id} = client.ol_context
|
||||
return callback(new Error("no project_id found on client")) if !project_id?
|
||||
|
||||
WebsocketController._assertClientCanApplyUpdate client, doc_id, update, (error) ->
|
||||
|
|
|
@ -7,8 +7,6 @@ HealthCheckManager = require "./HealthCheckManager"
|
|||
RoomManager = require "./RoomManager"
|
||||
ChannelManager = require "./ChannelManager"
|
||||
ConnectedUsersManager = require "./ConnectedUsersManager"
|
||||
Utils = require './Utils'
|
||||
Async = require 'async'
|
||||
|
||||
RESTRICTED_USER_MESSAGE_TYPE_PASS_LIST = [
|
||||
'connectionAccepted',
|
||||
|
@ -78,8 +76,15 @@ module.exports = WebsocketLoadBalancer =
|
|||
status = EventLogger.checkEventOrder("editor-events", message._id, message)
|
||||
if status is "duplicate"
|
||||
return # skip duplicate events
|
||||
|
||||
is_restricted_message = message.message not in RESTRICTED_USER_MESSAGE_TYPE_PASS_LIST
|
||||
|
||||
# send messages only to unique clients (due to duplicate entries in io.sockets.clients)
|
||||
clientList = io.sockets.clients(message.room_id)
|
||||
.filter((client) ->
|
||||
!(is_restricted_message && client.ol_context['is_restricted_user'])
|
||||
)
|
||||
|
||||
# avoid unnecessary work if no clients are connected
|
||||
return if clientList.length is 0
|
||||
logger.log {
|
||||
|
@ -90,20 +95,10 @@ module.exports = WebsocketLoadBalancer =
|
|||
socketIoClients: (client.id for client in clientList)
|
||||
}, "distributing event to clients"
|
||||
seen = {}
|
||||
# Send the messages to clients async, don't wait for them all to finish
|
||||
Async.eachLimit clientList
|
||||
, 2
|
||||
, (client, cb) ->
|
||||
Utils.getClientAttributes client, ['is_restricted_user'], (err, {is_restricted_user}) ->
|
||||
return cb(err) if err?
|
||||
for client in clientList
|
||||
if !seen[client.id]
|
||||
seen[client.id] = true
|
||||
if !(is_restricted_user && message.message not in RESTRICTED_USER_MESSAGE_TYPE_PASS_LIST)
|
||||
client.emit(message.message, message.payload...)
|
||||
cb()
|
||||
, (err) ->
|
||||
if err?
|
||||
logger.err {err, message}, "Error sending message to clients"
|
||||
client.emit(message.message, message.payload...)
|
||||
else if message.health_check?
|
||||
logger.debug {message}, "got health check message in editor events channel"
|
||||
HealthCheckManager.check channel, message.key
|
||||
|
|
|
@ -9,64 +9,56 @@ modulePath = '../../../app/js/AuthorizationManager'
|
|||
describe 'AuthorizationManager', ->
|
||||
beforeEach ->
|
||||
@client =
|
||||
params: {}
|
||||
get: (param, cb) ->
|
||||
cb null, @params[param]
|
||||
set: (param, value, cb) ->
|
||||
@params[param] = value
|
||||
cb()
|
||||
del: (param, cb) ->
|
||||
delete @params[param]
|
||||
cb()
|
||||
ol_context: {}
|
||||
|
||||
@AuthorizationManager = SandboxedModule.require modulePath, requires: {}
|
||||
|
||||
describe "assertClientCanViewProject", ->
|
||||
it "should allow the readOnly privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "readOnly"
|
||||
@client.ol_context.privilege_level = "readOnly"
|
||||
@AuthorizationManager.assertClientCanViewProject @client, (error) ->
|
||||
expect(error).to.be.null
|
||||
done()
|
||||
|
||||
it "should allow the readAndWrite privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "readAndWrite"
|
||||
@client.ol_context.privilege_level = "readAndWrite"
|
||||
@AuthorizationManager.assertClientCanViewProject @client, (error) ->
|
||||
expect(error).to.be.null
|
||||
done()
|
||||
|
||||
it "should allow the owner privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "owner"
|
||||
@client.ol_context.privilege_level = "owner"
|
||||
@AuthorizationManager.assertClientCanViewProject @client, (error) ->
|
||||
expect(error).to.be.null
|
||||
done()
|
||||
|
||||
it "should return an error with any other privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "unknown"
|
||||
@client.ol_context.privilege_level = "unknown"
|
||||
@AuthorizationManager.assertClientCanViewProject @client, (error) ->
|
||||
error.message.should.equal "not authorized"
|
||||
done()
|
||||
|
||||
describe "assertClientCanEditProject", ->
|
||||
it "should not allow the readOnly privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "readOnly"
|
||||
@client.ol_context.privilege_level = "readOnly"
|
||||
@AuthorizationManager.assertClientCanEditProject @client, (error) ->
|
||||
error.message.should.equal "not authorized"
|
||||
done()
|
||||
|
||||
it "should allow the readAndWrite privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "readAndWrite"
|
||||
@client.ol_context.privilege_level = "readAndWrite"
|
||||
@AuthorizationManager.assertClientCanEditProject @client, (error) ->
|
||||
expect(error).to.be.null
|
||||
done()
|
||||
|
||||
it "should allow the owner privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "owner"
|
||||
@client.ol_context.privilege_level = "owner"
|
||||
@AuthorizationManager.assertClientCanEditProject @client, (error) ->
|
||||
expect(error).to.be.null
|
||||
done()
|
||||
|
||||
it "should return an error with any other privilegeLevel", (done) ->
|
||||
@client.params.privilege_level = "unknown"
|
||||
@client.ol_context.privilege_level = "unknown"
|
||||
@AuthorizationManager.assertClientCanEditProject @client, (error) ->
|
||||
error.message.should.equal "not authorized"
|
||||
done()
|
||||
|
@ -77,11 +69,11 @@ describe 'AuthorizationManager', ->
|
|||
beforeEach () ->
|
||||
@doc_id = "12345"
|
||||
@callback = sinon.stub()
|
||||
@client.params = {}
|
||||
@client.ol_context = {}
|
||||
|
||||
describe "when not authorised at the project level", ->
|
||||
beforeEach () ->
|
||||
@client.params.privilege_level = "unknown"
|
||||
@client.ol_context.privilege_level = "unknown"
|
||||
|
||||
it "should not allow access", () ->
|
||||
@AuthorizationManager.assertClientCanViewProjectAndDoc @client, @doc_id, (err) ->
|
||||
|
@ -97,7 +89,7 @@ describe 'AuthorizationManager', ->
|
|||
|
||||
describe "when authorised at the project level", ->
|
||||
beforeEach () ->
|
||||
@client.params.privilege_level = "readOnly"
|
||||
@client.ol_context.privilege_level = "readOnly"
|
||||
|
||||
describe "and not authorised at the document level", ->
|
||||
it "should not allow access", () ->
|
||||
|
@ -127,11 +119,11 @@ describe 'AuthorizationManager', ->
|
|||
beforeEach () ->
|
||||
@doc_id = "12345"
|
||||
@callback = sinon.stub()
|
||||
@client.params = {}
|
||||
@client.ol_context = {}
|
||||
|
||||
describe "when not authorised at the project level", ->
|
||||
beforeEach () ->
|
||||
@client.params.privilege_level = "readOnly"
|
||||
@client.ol_context.privilege_level = "readOnly"
|
||||
|
||||
it "should not allow access", () ->
|
||||
@AuthorizationManager.assertClientCanEditProjectAndDoc @client, @doc_id, (err) ->
|
||||
|
@ -147,7 +139,7 @@ describe 'AuthorizationManager', ->
|
|||
|
||||
describe "when authorised at the project level", ->
|
||||
beforeEach () ->
|
||||
@client.params.privilege_level = "readAndWrite"
|
||||
@client.ol_context.privilege_level = "readAndWrite"
|
||||
|
||||
describe "and not authorised at the document level", ->
|
||||
it "should not allow access", () ->
|
||||
|
|
|
@ -23,9 +23,7 @@ describe 'WebsocketController', ->
|
|||
disconnected: false
|
||||
id: @client_id = "mock-client-id-123"
|
||||
publicId: "other-id-#{Math.random()}"
|
||||
params: {}
|
||||
set: sinon.stub()
|
||||
get: (param, cb) -> cb null, @params[param]
|
||||
ol_context: {}
|
||||
join: sinon.stub()
|
||||
leave: sinon.stub()
|
||||
@WebsocketController = SandboxedModule.require modulePath, requires:
|
||||
|
@ -69,38 +67,27 @@ describe 'WebsocketController', ->
|
|||
@RoomManager.joinProject.calledWith(@client, @project_id).should.equal true
|
||||
|
||||
it "should set the privilege level on the client", ->
|
||||
@client.set.calledWith("privilege_level", @privilegeLevel).should.equal true
|
||||
|
||||
@client.ol_context["privilege_level"].should.equal @privilegeLevel
|
||||
it "should set the user's id on the client", ->
|
||||
@client.set.calledWith("user_id", @user._id).should.equal true
|
||||
|
||||
@client.ol_context["user_id"].should.equal @user._id
|
||||
it "should set the user's email on the client", ->
|
||||
@client.set.calledWith("email", @user.email).should.equal true
|
||||
|
||||
@client.ol_context["email"].should.equal @user.email
|
||||
it "should set the user's first_name on the client", ->
|
||||
@client.set.calledWith("first_name", @user.first_name).should.equal true
|
||||
|
||||
@client.ol_context["first_name"].should.equal @user.first_name
|
||||
it "should set the user's last_name on the client", ->
|
||||
@client.set.calledWith("last_name", @user.last_name).should.equal true
|
||||
|
||||
@client.ol_context["last_name"].should.equal @user.last_name
|
||||
it "should set the user's sign up date on the client", ->
|
||||
@client.set.calledWith("signup_date", @user.signUpDate).should.equal true
|
||||
|
||||
@client.ol_context["signup_date"].should.equal @user.signUpDate
|
||||
it "should set the user's login_count on the client", ->
|
||||
@client.set.calledWith("login_count", @user.loginCount).should.equal true
|
||||
|
||||
@client.ol_context["login_count"].should.equal @user.loginCount
|
||||
it "should set the connected time on the client", ->
|
||||
@client.set.calledWith("connected_time", new Date()).should.equal true
|
||||
|
||||
@client.ol_context["connected_time"].should.equal new Date()
|
||||
it "should set the project_id on the client", ->
|
||||
@client.set.calledWith("project_id", @project_id).should.equal true
|
||||
|
||||
@client.ol_context["project_id"].should.equal @project_id
|
||||
it "should set the project owner id on the client", ->
|
||||
@client.set.calledWith("owner_id", @owner_id).should.equal true
|
||||
|
||||
@client.ol_context["owner_id"].should.equal @owner_id
|
||||
it "should set the is_restricted_user flag on the client", ->
|
||||
@client.set.calledWith("is_restricted_user", @isRestrictedUser).should.equal true
|
||||
|
||||
@client.ol_context["is_restricted_user"].should.equal @isRestrictedUser
|
||||
it "should call the callback with the project, privilegeLevel and protocolVersion", ->
|
||||
@callback
|
||||
.calledWith(null, @project, @privilegeLevel, @WebsocketController.PROTOCOL_VERSION)
|
||||
|
@ -191,14 +178,14 @@ describe 'WebsocketController', ->
|
|||
if room_id != @project_id
|
||||
throw "expected room_id to be project_id"
|
||||
return @clientsInRoom
|
||||
@client.params.project_id = @project_id
|
||||
@client.params.user_id = @user_id
|
||||
@client.ol_context.project_id = @project_id
|
||||
@client.ol_context.user_id = @user_id
|
||||
@WebsocketController.FLUSH_IF_EMPTY_DELAY = 0
|
||||
tk.reset() # Allow setTimeout to work.
|
||||
|
||||
describe "when the client did not joined a project yet", ->
|
||||
beforeEach (done) ->
|
||||
@client.params = {}
|
||||
@client.ol_context = {}
|
||||
@WebsocketController.leaveProject @io, @client, done
|
||||
|
||||
it "should bail out when calling leaveProject", () ->
|
||||
|
@ -248,8 +235,8 @@ describe 'WebsocketController', ->
|
|||
|
||||
describe "when client has not authenticated", ->
|
||||
beforeEach (done) ->
|
||||
@client.params.user_id = null
|
||||
@client.params.project_id = null
|
||||
@client.ol_context.user_id = null
|
||||
@client.ol_context.project_id = null
|
||||
@WebsocketController.leaveProject @io, @client, done
|
||||
|
||||
it "should not end clientTracking.clientDisconnected to the project room", ->
|
||||
|
@ -272,8 +259,8 @@ describe 'WebsocketController', ->
|
|||
|
||||
describe "when client has not joined a project", ->
|
||||
beforeEach (done) ->
|
||||
@client.params.user_id = @user_id
|
||||
@client.params.project_id = null
|
||||
@client.ol_context.user_id = @user_id
|
||||
@client.ol_context.project_id = null
|
||||
@WebsocketController.leaveProject @io, @client, done
|
||||
|
||||
it "should not end clientTracking.clientDisconnected to the project room", ->
|
||||
|
@ -303,8 +290,8 @@ describe 'WebsocketController', ->
|
|||
@ranges = { "mock": "ranges" }
|
||||
@options = {}
|
||||
|
||||
@client.params.project_id = @project_id
|
||||
@client.params.is_restricted_user = false
|
||||
@client.ol_context.project_id = @project_id
|
||||
@client.ol_context.is_restricted_user = false
|
||||
@AuthorizationManager.addAccessToDoc = sinon.stub()
|
||||
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, null)
|
||||
@DocumentUpdaterManager.getDocument = sinon.stub().callsArgWith(3, null, @doc_lines, @version, @ranges, @ops)
|
||||
|
@ -408,7 +395,7 @@ describe 'WebsocketController', ->
|
|||
describe "with a restricted client", ->
|
||||
beforeEach ->
|
||||
@ranges.comments = [{op: {a: 1}}, {op: {a: 2}}]
|
||||
@client.params.is_restricted_user = true
|
||||
@client.ol_context.is_restricted_user = true
|
||||
@WebsocketController.joinDoc @client, @doc_id, -1, @options, @callback
|
||||
|
||||
it "should overwrite ranges.comments with an empty list", ->
|
||||
|
@ -463,7 +450,7 @@ describe 'WebsocketController', ->
|
|||
describe "leaveDoc", ->
|
||||
beforeEach ->
|
||||
@doc_id = "doc-id-123"
|
||||
@client.params.project_id = @project_id
|
||||
@client.ol_context.project_id = @project_id
|
||||
@RoomManager.leaveDoc = sinon.stub()
|
||||
@WebsocketController.leaveDoc @client, @doc_id, @callback
|
||||
|
||||
|
@ -479,7 +466,7 @@ describe 'WebsocketController', ->
|
|||
|
||||
describe "getConnectedUsers", ->
|
||||
beforeEach ->
|
||||
@client.params.project_id = @project_id
|
||||
@client.ol_context.project_id = @project_id
|
||||
@users = ["mock", "users"]
|
||||
@WebsocketLoadBalancer.emitToRoom = sinon.stub()
|
||||
@ConnectedUsersManager.getConnectedUsers = sinon.stub().callsArgWith(1, null, @users)
|
||||
|
@ -527,7 +514,7 @@ describe 'WebsocketController', ->
|
|||
|
||||
describe "when restricted user", ->
|
||||
beforeEach ->
|
||||
@client.params.is_restricted_user = true
|
||||
@client.ol_context.is_restricted_user = true
|
||||
@AuthorizationManager.assertClientCanViewProject = sinon.stub().callsArgWith(1, null)
|
||||
@WebsocketController.getConnectedUsers @client, @callback
|
||||
|
||||
|
@ -564,14 +551,13 @@ describe 'WebsocketController', ->
|
|||
|
||||
describe "with a logged in user", ->
|
||||
beforeEach ->
|
||||
@clientParams = {
|
||||
@client.ol_context = {
|
||||
project_id: @project_id
|
||||
first_name: @first_name = "Douglas"
|
||||
last_name: @last_name = "Adams"
|
||||
email: @email = "joe@example.com"
|
||||
user_id: @user_id = "user-id-123"
|
||||
}
|
||||
@client.get = (param, callback) => callback null, @clientParams[param]
|
||||
@WebsocketController.updateClientPosition @client, @update
|
||||
|
||||
@populatedCursorData =
|
||||
|
@ -604,14 +590,13 @@ describe 'WebsocketController', ->
|
|||
|
||||
describe "with a logged in user who has no last_name set", ->
|
||||
beforeEach ->
|
||||
@clientParams = {
|
||||
@client.ol_context = {
|
||||
project_id: @project_id
|
||||
first_name: @first_name = "Douglas"
|
||||
last_name: undefined
|
||||
email: @email = "joe@example.com"
|
||||
user_id: @user_id = "user-id-123"
|
||||
}
|
||||
@client.get = (param, callback) => callback null, @clientParams[param]
|
||||
@WebsocketController.updateClientPosition @client, @update
|
||||
|
||||
@populatedCursorData =
|
||||
|
@ -644,14 +629,13 @@ describe 'WebsocketController', ->
|
|||
|
||||
describe "with a logged in user who has no first_name set", ->
|
||||
beforeEach ->
|
||||
@clientParams = {
|
||||
@client.ol_context = {
|
||||
project_id: @project_id
|
||||
first_name: undefined
|
||||
last_name: @last_name = "Adams"
|
||||
email: @email = "joe@example.com"
|
||||
user_id: @user_id = "user-id-123"
|
||||
}
|
||||
@client.get = (param, callback) => callback null, @clientParams[param]
|
||||
@WebsocketController.updateClientPosition @client, @update
|
||||
|
||||
@populatedCursorData =
|
||||
|
@ -683,14 +667,13 @@ describe 'WebsocketController', ->
|
|||
@metrics.inc.calledWith("editor.update-client-position", 0.1).should.equal true
|
||||
describe "with a logged in user who has no names set", ->
|
||||
beforeEach ->
|
||||
@clientParams = {
|
||||
@client.ol_context = {
|
||||
project_id: @project_id
|
||||
first_name: undefined
|
||||
last_name: undefined
|
||||
email: @email = "joe@example.com"
|
||||
user_id: @user_id = "user-id-123"
|
||||
}
|
||||
@client.get = (param, callback) => callback null, @clientParams[param]
|
||||
@WebsocketController.updateClientPosition @client, @update
|
||||
|
||||
it "should send the update to the project name with no name", ->
|
||||
|
@ -709,10 +692,9 @@ describe 'WebsocketController', ->
|
|||
|
||||
describe "with an anonymous user", ->
|
||||
beforeEach ->
|
||||
@clientParams = {
|
||||
@client.ol_context = {
|
||||
project_id: @project_id
|
||||
}
|
||||
@client.get = (param, callback) => callback null, @clientParams[param]
|
||||
@WebsocketController.updateClientPosition @client, @update
|
||||
|
||||
it "should send the update to the project room with no name", ->
|
||||
|
@ -745,8 +727,8 @@ describe 'WebsocketController', ->
|
|||
describe "applyOtUpdate", ->
|
||||
beforeEach ->
|
||||
@update = {op: {p: 12, t: "foo"}}
|
||||
@client.params.user_id = @user_id
|
||||
@client.params.project_id = @project_id
|
||||
@client.ol_context.user_id = @user_id
|
||||
@client.ol_context.project_id = @project_id
|
||||
@WebsocketController._assertClientCanApplyUpdate = sinon.stub().yields()
|
||||
@DocumentUpdaterManager.queueChange = sinon.stub().callsArg(3)
|
||||
|
||||
|
@ -807,8 +789,8 @@ describe 'WebsocketController', ->
|
|||
beforeEach (done) ->
|
||||
@client.disconnect = sinon.stub()
|
||||
@client.emit = sinon.stub()
|
||||
@client.params.user_id = @user_id
|
||||
@client.params.project_id = @project_id
|
||||
@client.ol_context.user_id = @user_id
|
||||
@client.ol_context.project_id = @project_id
|
||||
error = new Error("update is too large")
|
||||
error.updateSize = 7372835
|
||||
@DocumentUpdaterManager.queueChange = sinon.stub().callsArgWith(3, error)
|
||||
|
|
|
@ -18,12 +18,6 @@ describe "WebsocketLoadBalancer", ->
|
|||
"./RoomManager" : @RoomManager = {eventSource: sinon.stub().returns @RoomEvents}
|
||||
"./ChannelManager": @ChannelManager = {publish: sinon.stub()}
|
||||
"./ConnectedUsersManager": @ConnectedUsersManager = {refreshClient: sinon.stub()}
|
||||
"./Utils": @Utils = {
|
||||
getClientAttributes: sinon.spy(
|
||||
(client, _attrs, callback) ->
|
||||
callback(null, {is_restricted_user: !!client.__isRestricted})
|
||||
)
|
||||
}
|
||||
@io = {}
|
||||
@WebsocketLoadBalancer.rclientPubList = [{publish: sinon.stub()}]
|
||||
@WebsocketLoadBalancer.rclientSubList = [{
|
||||
|
@ -87,9 +81,9 @@ describe "WebsocketLoadBalancer", ->
|
|||
beforeEach ->
|
||||
@io.sockets =
|
||||
clients: sinon.stub().returns([
|
||||
{id: 'client-id-1', emit: @emit1 = sinon.stub()}
|
||||
{id: 'client-id-2', emit: @emit2 = sinon.stub()}
|
||||
{id: 'client-id-1', emit: @emit3 = sinon.stub()} # duplicate client
|
||||
{id: 'client-id-1', emit: @emit1 = sinon.stub(), ol_context: {}}
|
||||
{id: 'client-id-2', emit: @emit2 = sinon.stub(), ol_context: {}}
|
||||
{id: 'client-id-1', emit: @emit3 = sinon.stub(), ol_context: {}} # duplicate client
|
||||
])
|
||||
data = JSON.stringify
|
||||
room_id: @room_id
|
||||
|
@ -109,10 +103,10 @@ describe "WebsocketLoadBalancer", ->
|
|||
beforeEach ->
|
||||
@io.sockets =
|
||||
clients: sinon.stub().returns([
|
||||
{id: 'client-id-1', emit: @emit1 = sinon.stub()}
|
||||
{id: 'client-id-2', emit: @emit2 = sinon.stub()}
|
||||
{id: 'client-id-1', emit: @emit3 = sinon.stub()} # duplicate client
|
||||
{id: 'client-id-4', emit: @emit4 = sinon.stub(), __isRestricted: true}
|
||||
{id: 'client-id-1', emit: @emit1 = sinon.stub(), ol_context: {}}
|
||||
{id: 'client-id-2', emit: @emit2 = sinon.stub(), ol_context: {}}
|
||||
{id: 'client-id-1', emit: @emit3 = sinon.stub(), ol_context: {}} # duplicate client
|
||||
{id: 'client-id-4', emit: @emit4 = sinon.stub(), ol_context: {is_restricted_user: true}}
|
||||
])
|
||||
data = JSON.stringify
|
||||
room_id: @room_id
|
||||
|
@ -133,10 +127,10 @@ describe "WebsocketLoadBalancer", ->
|
|||
beforeEach ->
|
||||
@io.sockets =
|
||||
clients: sinon.stub().returns([
|
||||
{id: 'client-id-1', emit: @emit1 = sinon.stub()}
|
||||
{id: 'client-id-2', emit: @emit2 = sinon.stub()}
|
||||
{id: 'client-id-1', emit: @emit3 = sinon.stub()} # duplicate client
|
||||
{id: 'client-id-4', emit: @emit4 = sinon.stub(), __isRestricted: true}
|
||||
{id: 'client-id-1', emit: @emit1 = sinon.stub(), ol_context: {}}
|
||||
{id: 'client-id-2', emit: @emit2 = sinon.stub(), ol_context: {}}
|
||||
{id: 'client-id-1', emit: @emit3 = sinon.stub(), ol_context: {}} # duplicate client
|
||||
{id: 'client-id-4', emit: @emit4 = sinon.stub(), ol_context: {is_restricted_user: true}}
|
||||
])
|
||||
data = JSON.stringify
|
||||
room_id: @room_id
|
||||
|
|
|
@ -4,15 +4,10 @@ idCounter = 0
|
|||
|
||||
module.exports = class MockClient
|
||||
constructor: () ->
|
||||
@attributes = {}
|
||||
@ol_context = {}
|
||||
@join = sinon.stub()
|
||||
@emit = sinon.stub()
|
||||
@disconnect = sinon.stub()
|
||||
@id = idCounter++
|
||||
@publicId = idCounter++
|
||||
set : (key, value, callback) ->
|
||||
@attributes[key] = value
|
||||
callback() if callback?
|
||||
get : (key, callback) ->
|
||||
callback null, @attributes[key]
|
||||
disconnect: () ->
|
||||
|
|
Loading…
Reference in a new issue