UserSessionsManager.coffee 5.8 KB

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