UserSessionsManager.coffee 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. Settings = require('settings-sharelatex')
  2. redis = require('redis-sharelatex')
  3. logger = require("logger-sharelatex")
  4. Async = require('async')
  5. _ = require('underscore')
  6. rclient = redis.createClient(Settings.redis.web)
  7. module.exports = UserSessionsManager =
  8. _sessionSetKey: (user) ->
  9. return "UserSessions:#{user._id}"
  10. # mimic the key used by the express sessions
  11. _sessionKey: (sessionId) ->
  12. return "sess:#{sessionId}"
  13. trackSession: (user, sessionId, callback=(err)-> ) ->
  14. if !user?
  15. logger.log {sessionId}, "no user to track, returning"
  16. return callback(null)
  17. if !sessionId?
  18. logger.log {user_id: user._id}, "no sessionId to track, returning"
  19. return callback(null)
  20. logger.log {user_id: user._id, sessionId}, "onLogin handler"
  21. sessionSetKey = UserSessionsManager._sessionSetKey(user)
  22. value = UserSessionsManager._sessionKey sessionId
  23. rclient.multi()
  24. .sadd(sessionSetKey, value)
  25. .expire(sessionSetKey, "#{Settings.cookieSessionLength}")
  26. .exec (err, response) ->
  27. if err?
  28. logger.err {err, user_id: user._id, sessionSetKey}, "error while adding session key to UserSessions set"
  29. return callback(err)
  30. UserSessionsManager._checkSessions(user, () ->)
  31. callback()
  32. untrackSession: (user, sessionId, callback=(err)-> ) ->
  33. if !user?
  34. logger.log {sessionId}, "no user to untrack, returning"
  35. return callback(null)
  36. if !sessionId?
  37. logger.log {user_id: user._id}, "no sessionId to untrack, returning"
  38. return callback(null)
  39. logger.log {user_id: user._id, sessionId}, "onLogout handler"
  40. sessionSetKey = UserSessionsManager._sessionSetKey(user)
  41. value = UserSessionsManager._sessionKey sessionId
  42. rclient.multi()
  43. .srem(sessionSetKey, value)
  44. .expire(sessionSetKey, "#{Settings.cookieSessionLength}")
  45. .exec (err, response) ->
  46. if err?
  47. logger.err {err, user_id: user._id, sessionSetKey}, "error while removing session key from UserSessions set"
  48. return callback(err)
  49. UserSessionsManager._checkSessions(user, () ->)
  50. callback()
  51. getAllUserSessions: (user, exclude, callback=(err, sessionKeys)->) ->
  52. exclude = _.map(exclude, UserSessionsManager._sessionKey)
  53. sessionSetKey = UserSessionsManager._sessionSetKey(user)
  54. rclient.smembers sessionSetKey, (err, sessionKeys) ->
  55. if err?
  56. logger.err user_id: user._id, "error getting all session keys for user from redis"
  57. return callback(err)
  58. sessionKeys = _.filter sessionKeys, (k) -> !(_.contains(exclude, k))
  59. if sessionKeys.length == 0
  60. logger.log {user_id: user._id}, "no other sessions found, returning"
  61. return callback(null, [])
  62. rclient.mget sessionKeys, (err, sessions) ->
  63. if err?
  64. logger.err {user_id: user._id}, "error getting all sessions for user from redis"
  65. return callback(err)
  66. result = []
  67. for session in sessions
  68. if session is null
  69. continue
  70. session = JSON.parse(session)
  71. session_user = session?.user or session?.passport?.user
  72. result.push {
  73. ip_address: session_user.ip_address,
  74. session_created: session_user.session_created
  75. }
  76. return callback(null, result)
  77. revokeAllUserSessions: (user, retain, callback=(err)->) ->
  78. if !retain?
  79. retain = []
  80. retain = retain.map((i) -> UserSessionsManager._sessionKey(i))
  81. if !user?
  82. logger.log {}, "no user to revoke sessions for, returning"
  83. return callback(null)
  84. logger.log {user_id: user._id}, "revoking all existing sessions for user"
  85. sessionSetKey = UserSessionsManager._sessionSetKey(user)
  86. rclient.smembers sessionSetKey, (err, sessionKeys) ->
  87. if err?
  88. logger.err {err, user_id: user._id, sessionSetKey}, "error getting contents of UserSessions set"
  89. return callback(err)
  90. keysToDelete = _.filter(sessionKeys, (k) -> k not in retain)
  91. if keysToDelete.length == 0
  92. logger.log {user_id: user._id}, "no sessions in UserSessions set to delete, returning"
  93. return callback(null)
  94. logger.log {user_id: user._id, count: keysToDelete.length}, "deleting sessions for user"
  95. rclient.multi()
  96. .del(keysToDelete)
  97. .srem(sessionSetKey, keysToDelete)
  98. .exec (err, result) ->
  99. if err?
  100. logger.err {err, user_id: user._id, sessionSetKey}, "error revoking all sessions for user"
  101. return callback(err)
  102. callback(null)
  103. touch: (user, callback=(err)->) ->
  104. if !user
  105. logger.log {}, "no user to touch sessions for, returning"
  106. return callback(null)
  107. sessionSetKey = UserSessionsManager._sessionSetKey(user)
  108. rclient.expire sessionSetKey, "#{Settings.cookieSessionLength}", (err, response) ->
  109. if err?
  110. logger.err {err, user_id: user._id}, "error while updating ttl on UserSessions set"
  111. return callback(err)
  112. callback(null)
  113. _checkSessions: (user, callback=(err)->) ->
  114. if !user
  115. logger.log {}, "no user, returning"
  116. return callback(null)
  117. logger.log {user_id: user._id}, "checking sessions for user"
  118. sessionSetKey = UserSessionsManager._sessionSetKey(user)
  119. rclient.smembers sessionSetKey, (err, sessionKeys) ->
  120. if err?
  121. logger.err {err, user_id: user._id, sessionSetKey}, "error getting contents of UserSessions set"
  122. return callback(err)
  123. logger.log {user_id: user._id, count: sessionKeys.length}, "checking sessions for user"
  124. Async.series(
  125. sessionKeys.map(
  126. (key) ->
  127. (next) ->
  128. rclient.get key, (err, val) ->
  129. if err?
  130. return next(err)
  131. if !val?
  132. logger.log {user_id: user._id, key}, ">> removing key from UserSessions set"
  133. rclient.srem sessionSetKey, key, (err, result) ->
  134. if err?
  135. return next(err)
  136. return next(null)
  137. else
  138. next()
  139. )
  140. , (err, results) ->
  141. logger.log {user_id: user._id}, "done checking sessions for user"
  142. return callback(err)
  143. )