overleaf/services/web/app/coffee/Features/User/UserSessionsManager.coffee

130 lines
4.6 KiB
CoffeeScript
Raw Normal View History

Settings = require('settings-sharelatex')
redis = require('redis-sharelatex')
logger = require("logger-sharelatex")
2016-07-04 04:27:38 -04:00
Async = require('async')
2016-07-05 09:20:47 -04:00
_ = require('underscore')
2016-07-04 05:05:34 -04:00
rclient = redis.createClient(Settings.redis.web)
module.exports = UserSessionsManager =
_sessionSetKey: (user) ->
return "UserSessions:#{user._id}"
# mimic the key used by the express sessions
_sessionKey: (sessionId) ->
return "sess:#{sessionId}"
trackSession: (user, sessionId, callback=(err)-> ) ->
2016-07-01 10:55:50 -04:00
if !user
logger.log {sessionId}, "no user to track, returning"
return callback(null)
if !sessionId
logger.log {user_id: user._id}, "no sessionId to track, returning"
return callback(null)
logger.log {user_id: user._id, sessionId}, "onLogin handler"
sessionSetKey = UserSessionsManager._sessionSetKey(user)
value = UserSessionsManager._sessionKey sessionId
2016-07-01 06:24:46 -04:00
rclient.multi()
.sadd(sessionSetKey, value)
.expire(sessionSetKey, "#{Settings.cookieSessionLength}")
.exec (err, response) ->
if err
2016-07-01 08:37:56 -04:00
logger.err {err, user_id: user._id, sessionSetKey}, "error while adding session key to UserSessions set"
2016-07-01 06:24:46 -04:00
return callback(err)
2016-07-04 05:37:01 -04:00
UserSessionsManager._checkSessions(user, () ->)
2016-07-01 06:24:46 -04:00
callback()
untrackSession: (user, sessionId, callback=(err)-> ) ->
2016-07-01 10:55:50 -04:00
if !user
logger.log {sessionId}, "no user to untrack, returning"
return callback(null)
if !sessionId
logger.log {user_id: user._id}, "no sessionId to untrack, returning"
return callback(null)
logger.log {user_id: user._id, sessionId}, "onLogout handler"
if !user
logger.log {sessionId}, "no user, for some reason"
return callback()
sessionSetKey = UserSessionsManager._sessionSetKey(user)
value = UserSessionsManager._sessionKey sessionId
2016-07-01 06:24:46 -04:00
rclient.multi()
.srem(sessionSetKey, value)
.expire(sessionSetKey, "#{Settings.cookieSessionLength}")
.exec (err, response) ->
if err
2016-07-01 08:37:56 -04:00
logger.err {err, user_id: user._id, sessionSetKey}, "error while removing session key from UserSessions set"
2016-07-01 06:24:46 -04:00
return callback(err)
2016-07-04 05:37:01 -04:00
UserSessionsManager._checkSessions(user, () ->)
2016-07-01 06:24:46 -04:00
callback()
2016-07-05 09:20:47 -04:00
revokeAllUserSessions: (user, retain, callback=(err)->) ->
if !retain
retain = []
2016-07-05 09:54:26 -04:00
retain = retain.map((i) -> UserSessionsManager._sessionKey(i))
2016-07-01 10:55:50 -04:00
if !user
logger.log {}, "no user to revoke sessions for, returning"
return callback(null)
logger.log {user_id: user._id}, "revoking all existing sessions for user"
2016-07-01 08:38:13 -04:00
sessionSetKey = UserSessionsManager._sessionSetKey(user)
rclient.smembers sessionSetKey, (err, sessionKeys) ->
if err
logger.err {err, user_id: user._id, sessionSetKey}, "error getting contents of UserSessions set"
return callback(err)
2016-07-05 09:54:26 -04:00
keysToDelete = _.filter(sessionKeys, (k) -> k not in retain)
if keysToDelete.length == 0
logger.log {user_id: user._id}, "no sessions in UserSessions set to delete, returning"
return callback(null)
2016-07-05 09:20:47 -04:00
logger.log {user_id: user._id, count: keysToDelete.length}, "deleting sessions for user"
2016-07-01 08:38:13 -04:00
rclient.multi()
2016-07-05 09:20:47 -04:00
.del(keysToDelete)
.srem(sessionSetKey, keysToDelete)
2016-07-01 08:38:13 -04:00
.exec (err, result) ->
if err
logger.err {err, user_id: user._id, sessionSetKey}, "error revoking all sessions for user"
return callback(err)
callback(null)
2016-07-01 06:24:46 -04:00
touch: (user, callback=(err)->) ->
if !user
2016-07-01 10:55:50 -04:00
logger.log {}, "no user to touch sessions for, returning"
2016-07-01 06:24:46 -04:00
return callback(null)
sessionSetKey = UserSessionsManager._sessionSetKey(user)
rclient.expire sessionSetKey, "#{Settings.cookieSessionLength}", (err, response) ->
if err
logger.err {err, user_id: user._id}, "error while updating ttl on UserSessions set"
return callback(err)
2016-07-04 09:04:10 -04:00
callback(null)
2016-07-04 04:27:38 -04:00
_checkSessions: (user, callback=(err)->) ->
if !user
logger.log {}, "no user, returning"
return callback(null)
logger.log {user_id: user._id}, "checking sessions for user"
sessionSetKey = UserSessionsManager._sessionSetKey(user)
rclient.smembers sessionSetKey, (err, sessionKeys) ->
if err
logger.err {err, user_id: user._id, sessionSetKey}, "error getting contents of UserSessions set"
return callback(err)
logger.log {user_id: user._id, count: sessionKeys.length}, "checking sessions for user"
Async.series(
sessionKeys.map(
(key) ->
(next) ->
rclient.get key, (err, val) ->
if err
return next(err)
if val == null
logger.log {user_id: user._id, key}, ">> removing key from UserSessions set"
rclient.srem sessionSetKey, key, (err, result) ->
if err
return next(err)
return next(null)
else
next()
)
, (err, results) ->
logger.log {user_id: user._id}, "done checking sessions for user"
return callback(err)
)