瀏覽代碼

[misc] vendor a patched session.socket.io middleware

Jakob Ackermann 6 年之前
父節點
當前提交
dc553c4150

+ 1 - 1
services/real-time/app.coffee

@@ -17,7 +17,7 @@ if Settings.sentry?.dsn?
 sessionRedisClient = redis.createClient(Settings.redis.websessions)
 
 RedisStore = require('connect-redis')(session)
-SessionSockets = require('session.socket.io')
+SessionSockets = require('./app/js/SessionSockets')
 CookieParser = require("cookie-parser")
 
 DrainManager = require("./app/js/DrainManager")

+ 23 - 0
services/real-time/app/coffee/SessionSockets.coffee

@@ -0,0 +1,23 @@
+{EventEmitter} = require('events')
+
+module.exports = (io, sessionStore, cookieParser, cookieName) ->
+	missingSessionError = new Error('could not look up session by key')
+
+	sessionSockets = new EventEmitter()
+	next = (error, socket, session) ->
+		sessionSockets.emit 'connection', error, socket, session
+
+	io.on 'connection', (socket) ->
+		req = socket.handshake
+		cookieParser req, {}, () ->
+			sessionId = req.signedCookies and req.signedCookies[cookieName]
+			if not sessionId
+				return next(missingSessionError, socket)
+			sessionStore.get sessionId, (error, session) ->
+				if error
+					return next(error, socket)
+				if not session
+					return next(missingSessionError, socket)
+				next(null, socket, session)
+
+	return sessionSockets

+ 0 - 5
services/real-time/package-lock.json

@@ -2165,11 +2165,6 @@
         "send": "0.16.2"
       }
     },
-    "session.socket.io": {
-      "version": "0.1.6",
-      "resolved": "https://registry.npmjs.org/session.socket.io/-/session.socket.io-0.1.6.tgz",
-      "integrity": "sha1-vh7sJAYJWgP4dw6ozN5s8SYBxdA="
-    },
     "setprototypeof": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",

+ 0 - 1
services/real-time/package.json

@@ -33,7 +33,6 @@
     "metrics-sharelatex": "^2.6.2",
     "redis-sharelatex": "^1.0.12",
     "request": "^2.88.0",
-    "session.socket.io": "^0.1.6",
     "settings-sharelatex": "^1.1.0",
     "socket.io": "0.9.19",
     "socket.io-client": "^0.9.16"

+ 67 - 0
services/real-time/test/acceptance/coffee/SessionSocketsTests.coffee

@@ -0,0 +1,67 @@
+RealTimeClient = require("./helpers/RealTimeClient")
+Settings = require("settings-sharelatex")
+{expect} = require('chai')
+
+describe 'SessionSockets', ->
+	before ->
+		@checkSocket = (fn) ->
+			client = RealTimeClient.connect()
+			client.on 'connectionAccepted', fn
+			client.on 'connectionRejected', fn
+			return null
+
+	describe 'without cookies', ->
+		before ->
+			RealTimeClient.cookie = null
+
+		it 'should return a lookup error', (done) ->
+			@checkSocket (error) ->
+				expect(error).to.exist
+				expect(error.message).to.equal('invalid session')
+				done()
+
+	describe 'with a different cookie', ->
+		before ->
+			RealTimeClient.cookie = "some.key=someValue"
+
+		it 'should return a lookup error', (done) ->
+			@checkSocket (error) ->
+				expect(error).to.exist
+				expect(error.message).to.equal('invalid session')
+				done()
+
+	describe 'with an invalid cookie', ->
+		before (done) ->
+			RealTimeClient.setSession {}, (error) ->
+				return done(error) if error
+				RealTimeClient.cookie = "#{Settings.cookieName}=#{
+					RealTimeClient.cookie.slice(17, 49)
+				}"
+				done()
+			return null
+
+		it 'should return a lookup error', (done) ->
+			@checkSocket (error) ->
+				expect(error).to.exist
+				expect(error.message).to.equal('invalid session')
+				done()
+
+	describe 'with a valid cookie and no matching session', ->
+		before ->
+			RealTimeClient.cookie = "#{Settings.cookieName}=unknownId"
+
+		it 'should return a lookup error', (done) ->
+			@checkSocket (error) ->
+				expect(error).to.exist
+				expect(error.message).to.equal('invalid session')
+				done()
+
+	describe 'with a valid cookie and a matching session', ->
+		before (done) ->
+			RealTimeClient.setSession({}, done)
+			return null
+
+		it 'should not return an error', (done) ->
+			@checkSocket (error) ->
+				expect(error).to.not.exist
+				done()

+ 126 - 0
services/real-time/test/unit/coffee/SessionSocketsTests.coffee

@@ -0,0 +1,126 @@
+{EventEmitter} = require('events')
+{expect} = require('chai')
+SandboxedModule = require('sandboxed-module')
+modulePath = '../../../app/js/SessionSockets'
+sinon = require('sinon')
+
+describe 'SessionSockets', ->
+	before ->
+		@SessionSocketsModule = SandboxedModule.require modulePath
+		@io = new EventEmitter()
+		@id1 = Math.random().toString()
+		@id2 = Math.random().toString()
+		redisResponses =
+			error: [new Error('Redis: something went wrong'), null]
+			unknownId: [null, null]
+		redisResponses[@id1] = [null, {user: {_id: '123'}}]
+		redisResponses[@id2] = [null, {user: {_id: 'abc'}}]
+
+		@sessionStore =
+			get: sinon.stub().callsFake (id, fn) ->
+				fn.apply(null, redisResponses[id])
+		@cookieParser = (req, res, next) ->
+			req.signedCookies = req._signedCookies
+			next()
+		@SessionSockets = @SessionSocketsModule(@io, @sessionStore, @cookieParser, 'ol.sid')
+		@checkSocket = (socket, fn) =>
+			@SessionSockets.once('connection', fn)
+			@io.emit('connection', socket)
+
+	describe 'without cookies', ->
+		before ->
+			@socket = {handshake: {}}
+
+		it 'should return a lookup error', (done) ->
+			@checkSocket @socket, (error) ->
+				expect(error).to.exist
+				expect(error.message).to.equal('could not look up session by key')
+				done()
+
+		it 'should not query redis', (done) ->
+			@checkSocket @socket, () =>
+				expect(@sessionStore.get.called).to.equal(false)
+				done()
+
+	describe 'with a different cookie', ->
+		before ->
+			@socket = {handshake: {_signedCookies: {other: 1}}}
+
+		it 'should return a lookup error', (done) ->
+			@checkSocket @socket, (error) ->
+				expect(error).to.exist
+				expect(error.message).to.equal('could not look up session by key')
+				done()
+
+		it 'should not query redis', (done) ->
+			@checkSocket @socket, () =>
+				expect(@sessionStore.get.called).to.equal(false)
+				done()
+
+	describe 'with a valid cookie and a failing session lookup', ->
+		before ->
+			@socket = {handshake: {_signedCookies: {'ol.sid': 'error'}}}
+
+		it 'should query redis', (done) ->
+			@checkSocket @socket, () =>
+				expect(@sessionStore.get.called).to.equal(true)
+				done()
+
+		it 'should return a redis error', (done) ->
+			@checkSocket @socket, (error) ->
+				expect(error).to.exist
+				expect(error.message).to.equal('Redis: something went wrong')
+				done()
+
+	describe 'with a valid cookie and no matching session', ->
+		before ->
+			@socket = {handshake: {_signedCookies: {'ol.sid': 'unknownId'}}}
+
+		it 'should query redis', (done) ->
+			@checkSocket @socket, () =>
+				expect(@sessionStore.get.called).to.equal(true)
+				done()
+
+		it 'should return a lookup error', (done) ->
+			@checkSocket @socket, (error) ->
+				expect(error).to.exist
+				expect(error.message).to.equal('could not look up session by key')
+				done()
+
+	describe 'with a valid cookie and a matching session', ->
+		before ->
+			@socket = {handshake: {_signedCookies: {'ol.sid': @id1}}}
+
+		it 'should query redis', (done) ->
+			@checkSocket @socket, () =>
+				expect(@sessionStore.get.called).to.equal(true)
+				done()
+
+		it 'should not return an error', (done) ->
+			@checkSocket @socket, (error) ->
+				expect(error).to.not.exist
+				done()
+
+		it 'should return the session', (done) ->
+			@checkSocket @socket, (error, s, session) ->
+				expect(session).to.deep.equal({user: {_id: '123'}})
+				done()
+
+	describe 'with a different valid cookie and matching session', ->
+		before ->
+			@socket = {handshake: {_signedCookies: {'ol.sid': @id2}}}
+
+		it 'should query redis', (done) ->
+			@checkSocket @socket, () =>
+				expect(@sessionStore.get.called).to.equal(true)
+				done()
+
+		it 'should not return an error', (done) ->
+			@checkSocket @socket, (error) ->
+				expect(error).to.not.exist
+				done()
+
+		it 'should return the other session', (done) ->
+			@checkSocket @socket, (error, s, session) ->
+				expect(session).to.deep.equal({user: {_id: 'abc'}})
+				done()