| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- const OError = require('@overleaf/o-error')
- const Settings = require('@overleaf/settings')
- const logger = require('logger-sharelatex')
- const Async = require('async')
- const _ = require('underscore')
- const { promisify } = require('util')
- const UserSessionsRedis = require('./UserSessionsRedis')
- const rclient = UserSessionsRedis.client()
- const UserSessionsManager = {
- // mimic the key used by the express sessions
- _sessionKey(sessionId) {
- return `sess:${sessionId}`
- },
- trackSession(user, sessionId, callback) {
- if (!user) {
- return callback(null)
- }
- if (!sessionId) {
- return callback(null)
- }
- const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
- const value = UserSessionsManager._sessionKey(sessionId)
- rclient
- .multi()
- .sadd(sessionSetKey, value)
- .pexpire(sessionSetKey, `${Settings.cookieSessionLength}`) // in milliseconds
- .exec(function (err, response) {
- if (err) {
- OError.tag(
- err,
- 'error while adding session key to UserSessions set',
- {
- user_id: user._id,
- sessionSetKey,
- }
- )
- return callback(err)
- }
- UserSessionsManager._checkSessions(user, function () {})
- callback()
- })
- },
- untrackSession(user, sessionId, callback) {
- if (!callback) {
- callback = function () {}
- }
- if (!user) {
- return callback(null)
- }
- if (!sessionId) {
- return callback(null)
- }
- const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
- const value = UserSessionsManager._sessionKey(sessionId)
- rclient
- .multi()
- .srem(sessionSetKey, value)
- .pexpire(sessionSetKey, `${Settings.cookieSessionLength}`) // in milliseconds
- .exec(function (err, response) {
- if (err) {
- OError.tag(
- err,
- 'error while removing session key from UserSessions set',
- {
- user_id: user._id,
- sessionSetKey,
- }
- )
- return callback(err)
- }
- UserSessionsManager._checkSessions(user, function () {})
- callback()
- })
- },
- getAllUserSessions(user, exclude, callback) {
- exclude = _.map(exclude, UserSessionsManager._sessionKey)
- const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
- rclient.smembers(sessionSetKey, function (err, sessionKeys) {
- if (err) {
- OError.tag(err, 'error getting all session keys for user from redis', {
- user_id: user._id,
- })
- 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),
- function (err, sessions) {
- if (err) {
- OError.tag(err, 'error getting all sessions for user from redis', {
- user_id: user._id,
- })
- return callback(err)
- }
- const result = []
- for (let session of Array.from(sessions)) {
- if (!session) {
- continue
- }
- session = JSON.parse(session)
- let sessionUser = session.passport && session.passport.user
- if (!sessionUser) {
- sessionUser = session.user
- }
- result.push({
- ip_address: sessionUser.ip_address,
- session_created: sessionUser.session_created,
- })
- }
- callback(null, result)
- }
- )
- })
- },
- revokeAllUserSessions(user, retain, callback) {
- if (!retain) {
- retain = []
- }
- retain = retain.map(i => UserSessionsManager._sessionKey(i))
- if (!user) {
- return callback(null)
- }
- const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
- rclient.smembers(sessionSetKey, function (err, sessionKeys) {
- if (err) {
- OError.tag(err, 'error getting contents of UserSessions set', {
- user_id: user._id,
- sessionSetKey,
- })
- return callback(err)
- }
- const keysToDelete = _.filter(
- sessionKeys,
- k => !Array.from(retain).includes(k)
- )
- 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'
- )
- const deletions = keysToDelete.map(k => cb => rclient.del(k, cb))
- Async.series(deletions, function (err, _result) {
- if (err) {
- OError.tag(err, 'error revoking all sessions for user', {
- user_id: user._id,
- sessionSetKey,
- })
- return callback(err)
- }
- rclient.srem(sessionSetKey, keysToDelete, function (err) {
- if (err) {
- OError.tag(err, 'error removing session set for user', {
- user_id: user._id,
- sessionSetKey,
- })
- return callback(err)
- }
- callback(null)
- })
- })
- })
- },
- touch(user, callback) {
- if (!user) {
- return callback(null)
- }
- const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
- rclient.pexpire(
- sessionSetKey,
- `${Settings.cookieSessionLength}`, // in milliseconds
- function (err, response) {
- if (err) {
- OError.tag(err, 'error while updating ttl on UserSessions set', {
- user_id: user._id,
- })
- return callback(err)
- }
- callback(null)
- }
- )
- },
- _checkSessions(user, callback) {
- if (!user) {
- return callback(null)
- }
- const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
- rclient.smembers(sessionSetKey, function (err, sessionKeys) {
- if (err) {
- OError.tag(err, 'error getting contents of UserSessions set', {
- user_id: user._id,
- sessionSetKey,
- })
- return callback(err)
- }
- Async.series(
- sessionKeys.map(key => next =>
- rclient.get(key, function (err, val) {
- if (err) {
- return next(err)
- }
- if (!val) {
- rclient.srem(sessionSetKey, key, function (err, result) {
- return next(err)
- })
- } else {
- next()
- }
- })
- ),
- function (err, results) {
- callback(err)
- }
- )
- })
- },
- }
- UserSessionsManager.promises = {
- getAllUserSessions: promisify(UserSessionsManager.getAllUserSessions),
- revokeAllUserSessions: promisify(UserSessionsManager.revokeAllUserSessions),
- }
- module.exports = UserSessionsManager
|