| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- Settings = require('settings-sharelatex')
- logger = require("logger-sharelatex")
- Async = require('async')
- _ = require('underscore')
- UserSessionsRedis = require('./UserSessionsRedis')
- rclient = UserSessionsRedis.client()
- module.exports = UserSessionsManager =
- # mimic the key used by the express sessions
- _sessionKey: (sessionId) ->
- return "sess:#{sessionId}"
- trackSession: (user, sessionId, callback=(err)-> ) ->
- 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 = UserSessionsRedis.sessionSetKey(user)
- value = UserSessionsManager._sessionKey sessionId
- rclient.multi()
- .sadd(sessionSetKey, value)
- .expire(sessionSetKey, "#{Settings.cookieSessionLength}")
- .exec (err, response) ->
- if err?
- logger.err {err, user_id: user._id, sessionSetKey}, "error while adding session key to UserSessions set"
- return callback(err)
- UserSessionsManager._checkSessions(user, () ->)
- callback()
- untrackSession: (user, sessionId, callback=(err)-> ) ->
- 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"
- sessionSetKey = UserSessionsRedis.sessionSetKey(user)
- value = UserSessionsManager._sessionKey sessionId
- rclient.multi()
- .srem(sessionSetKey, value)
- .expire(sessionSetKey, "#{Settings.cookieSessionLength}")
- .exec (err, response) ->
- if err?
- logger.err {err, user_id: user._id, sessionSetKey}, "error while removing session key from UserSessions set"
- return callback(err)
- UserSessionsManager._checkSessions(user, () ->)
- callback()
- getAllUserSessions: (user, exclude, callback=(err, sessionKeys)->) ->
- exclude = _.map(exclude, UserSessionsManager._sessionKey)
- sessionSetKey = UserSessionsRedis.sessionSetKey(user)
- rclient.smembers sessionSetKey, (err, sessionKeys) ->
- if err?
- logger.err user_id: user._id, "error getting all session keys for user from redis"
- return callback(err)
- sessionKeys = _.filter sessionKeys, (k) -> !(_.contains(exclude, k))
- if sessionKeys.length == 0
- logger.log {user_id: user._id}, "no other sessions found, returning"
- return callback(null, [])
- Async.mapSeries sessionKeys, ((k, cb) -> rclient.get(k, cb)), (err, sessions) ->
- if err?
- logger.err {user_id: user._id}, "error getting all sessions for user from redis"
- return callback(err)
- result = []
- for session in sessions
- if session is null
- continue
- session = JSON.parse(session)
- session_user = session?.user or session?.passport?.user
- result.push {
- ip_address: session_user.ip_address,
- session_created: session_user.session_created
- }
- return callback(null, result)
- revokeAllUserSessions: (user, retain, callback=(err)->) ->
- if !retain?
- retain = []
- retain = retain.map((i) -> UserSessionsManager._sessionKey(i))
- 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"
- sessionSetKey = UserSessionsRedis.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)
- 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)
- logger.log {user_id: user._id, count: keysToDelete.length}, "deleting sessions for user"
- deletions = keysToDelete.map (k) ->
- (cb) ->
- rclient.del k, cb
- Async.series deletions, (err, _result) ->
- if err?
- logger.err {err, user_id: user._id, sessionSetKey}, "errror revoking all sessions for user"
- return callback(err)
- rclient.srem sessionSetKey, keysToDelete, (err) ->
- if err?
- logger.err {err, user_id: user._id, sessionSetKey}, "error removing session set for user"
- return callback(err)
- callback(null)
- touch: (user, callback=(err)->) ->
- if !user?
- logger.log {}, "no user to touch sessions for, returning"
- return callback(null)
- sessionSetKey = UserSessionsRedis.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)
- callback(null)
- _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 = UserSessionsRedis.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?
- 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)
- )
|