UserSessionsManager.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. const OError = require('@overleaf/o-error')
  2. const Settings = require('@overleaf/settings')
  3. const logger = require('@overleaf/logger')
  4. const Async = require('async')
  5. const _ = require('underscore')
  6. const { promisify } = require('util')
  7. const UserSessionsRedis = require('./UserSessionsRedis')
  8. const rclient = UserSessionsRedis.client()
  9. const UserSessionsManager = {
  10. // mimic the key used by the express sessions
  11. _sessionKey(sessionId) {
  12. return `sess:${sessionId}`
  13. },
  14. trackSession(user, sessionId, callback) {
  15. if (!user) {
  16. return callback(null)
  17. }
  18. if (!sessionId) {
  19. return callback(null)
  20. }
  21. const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
  22. const value = UserSessionsManager._sessionKey(sessionId)
  23. rclient
  24. .multi()
  25. .sadd(sessionSetKey, value)
  26. .pexpire(sessionSetKey, `${Settings.cookieSessionLength}`) // in milliseconds
  27. .exec(function (err, response) {
  28. if (err) {
  29. OError.tag(
  30. err,
  31. 'error while adding session key to UserSessions set',
  32. {
  33. user_id: user._id,
  34. sessionSetKey,
  35. }
  36. )
  37. return callback(err)
  38. }
  39. UserSessionsManager._checkSessions(user, function () {})
  40. callback()
  41. })
  42. },
  43. untrackSession(user, sessionId, callback) {
  44. if (!callback) {
  45. callback = function () {}
  46. }
  47. if (!user) {
  48. return callback(null)
  49. }
  50. if (!sessionId) {
  51. return callback(null)
  52. }
  53. const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
  54. const value = UserSessionsManager._sessionKey(sessionId)
  55. rclient
  56. .multi()
  57. .srem(sessionSetKey, value)
  58. .pexpire(sessionSetKey, `${Settings.cookieSessionLength}`) // in milliseconds
  59. .exec(function (err, response) {
  60. if (err) {
  61. OError.tag(
  62. err,
  63. 'error while removing session key from UserSessions set',
  64. {
  65. user_id: user._id,
  66. sessionSetKey,
  67. }
  68. )
  69. return callback(err)
  70. }
  71. UserSessionsManager._checkSessions(user, function () {})
  72. callback()
  73. })
  74. },
  75. getAllUserSessions(user, exclude, callback) {
  76. exclude = _.map(exclude, UserSessionsManager._sessionKey)
  77. const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
  78. rclient.smembers(sessionSetKey, function (err, sessionKeys) {
  79. if (err) {
  80. OError.tag(err, 'error getting all session keys for user from redis', {
  81. user_id: user._id,
  82. })
  83. return callback(err)
  84. }
  85. sessionKeys = _.filter(sessionKeys, k => !_.contains(exclude, k))
  86. if (sessionKeys.length === 0) {
  87. logger.log({ user_id: user._id }, 'no other sessions found, returning')
  88. return callback(null, [])
  89. }
  90. Async.mapSeries(
  91. sessionKeys,
  92. (k, cb) => rclient.get(k, cb),
  93. function (err, sessions) {
  94. if (err) {
  95. OError.tag(err, 'error getting all sessions for user from redis', {
  96. user_id: user._id,
  97. })
  98. return callback(err)
  99. }
  100. const result = []
  101. for (let session of Array.from(sessions)) {
  102. if (!session) {
  103. continue
  104. }
  105. session = JSON.parse(session)
  106. let sessionUser = session.passport && session.passport.user
  107. if (!sessionUser) {
  108. sessionUser = session.user
  109. }
  110. result.push({
  111. ip_address: sessionUser.ip_address,
  112. session_created: sessionUser.session_created,
  113. })
  114. }
  115. callback(null, result)
  116. }
  117. )
  118. })
  119. },
  120. revokeAllUserSessions(user, retain, callback) {
  121. if (!retain) {
  122. retain = []
  123. }
  124. retain = retain.map(i => UserSessionsManager._sessionKey(i))
  125. if (!user) {
  126. return callback(null)
  127. }
  128. const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
  129. rclient.smembers(sessionSetKey, function (err, sessionKeys) {
  130. if (err) {
  131. OError.tag(err, 'error getting contents of UserSessions set', {
  132. user_id: user._id,
  133. sessionSetKey,
  134. })
  135. return callback(err)
  136. }
  137. const keysToDelete = _.filter(
  138. sessionKeys,
  139. k => !Array.from(retain).includes(k)
  140. )
  141. if (keysToDelete.length === 0) {
  142. logger.log(
  143. { user_id: user._id },
  144. 'no sessions in UserSessions set to delete, returning'
  145. )
  146. return callback(null)
  147. }
  148. logger.log(
  149. { user_id: user._id, count: keysToDelete.length },
  150. 'deleting sessions for user'
  151. )
  152. const deletions = keysToDelete.map(k => cb => rclient.del(k, cb))
  153. Async.series(deletions, function (err, _result) {
  154. if (err) {
  155. OError.tag(err, 'error revoking all sessions for user', {
  156. user_id: user._id,
  157. sessionSetKey,
  158. })
  159. return callback(err)
  160. }
  161. rclient.srem(sessionSetKey, keysToDelete, function (err) {
  162. if (err) {
  163. OError.tag(err, 'error removing session set for user', {
  164. user_id: user._id,
  165. sessionSetKey,
  166. })
  167. return callback(err)
  168. }
  169. callback(null)
  170. })
  171. })
  172. })
  173. },
  174. touch(user, callback) {
  175. if (!user) {
  176. return callback(null)
  177. }
  178. const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
  179. rclient.pexpire(
  180. sessionSetKey,
  181. `${Settings.cookieSessionLength}`, // in milliseconds
  182. function (err, response) {
  183. if (err) {
  184. OError.tag(err, 'error while updating ttl on UserSessions set', {
  185. user_id: user._id,
  186. })
  187. return callback(err)
  188. }
  189. callback(null)
  190. }
  191. )
  192. },
  193. _checkSessions(user, callback) {
  194. if (!user) {
  195. return callback(null)
  196. }
  197. const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
  198. rclient.smembers(sessionSetKey, function (err, sessionKeys) {
  199. if (err) {
  200. OError.tag(err, 'error getting contents of UserSessions set', {
  201. user_id: user._id,
  202. sessionSetKey,
  203. })
  204. return callback(err)
  205. }
  206. Async.series(
  207. sessionKeys.map(
  208. key => next =>
  209. rclient.get(key, function (err, val) {
  210. if (err) {
  211. return next(err)
  212. }
  213. if (!val) {
  214. rclient.srem(sessionSetKey, key, function (err, result) {
  215. return next(err)
  216. })
  217. } else {
  218. next()
  219. }
  220. })
  221. ),
  222. function (err, results) {
  223. callback(err)
  224. }
  225. )
  226. })
  227. },
  228. }
  229. UserSessionsManager.promises = {
  230. getAllUserSessions: promisify(UserSessionsManager.getAllUserSessions),
  231. revokeAllUserSessions: promisify(UserSessionsManager.revokeAllUserSessions),
  232. }
  233. module.exports = UserSessionsManager