Merge pull request #2163 from overleaf/ta-decaf-cleanup-user

Complete Decafeinate of User Feature

GitOrigin-RevId: b8d7ebc59c4f6673392b4a0f33fb11e002d5a3a0
This commit is contained in:
Timothée Alby 2019-09-24 10:43:43 +02:00 committed by sharelatex
parent 2031115f48
commit c1c1b85a40
8 changed files with 200 additions and 405 deletions

View file

@ -1,18 +1,3 @@
/* eslint-disable
camelcase,
handle-callback-err,
max-len,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let UserEmailsConfirmationHandler
const EmailHelper = require('../Helpers/EmailHelper')
const EmailHandler = require('../Email/EmailHandler')
const OneTimeTokenHandler = require('../Security/OneTimeTokenHandler')
@ -24,11 +9,8 @@ const UserGetter = require('./UserGetter')
const ONE_YEAR_IN_S = 365 * 24 * 60 * 60
module.exports = UserEmailsConfirmationHandler = {
sendConfirmationEmail(user_id, email, emailTemplate, callback) {
if (callback == null) {
callback = function(error) {}
}
const UserEmailsConfirmationHandler = {
sendConfirmationEmail(userId, email, emailTemplate, callback) {
if (arguments.length === 3) {
callback = emailTemplate
emailTemplate = 'confirmEmail'
@ -41,16 +23,16 @@ module.exports = UserEmailsConfirmationHandler = {
}
email = EmailHelper.parseEmail(email)
if (email == null) {
if (!email) {
return callback(new Error('invalid email'))
}
const data = { user_id, email }
return OneTimeTokenHandler.getNewToken(
const data = { user_id: userId, email }
OneTimeTokenHandler.getNewToken(
'email_confirmation',
data,
{ expiresIn: ONE_YEAR_IN_S },
function(err, token) {
if (err != null) {
if (err) {
return callback(err)
}
const emailOptions = {
@ -58,49 +40,49 @@ module.exports = UserEmailsConfirmationHandler = {
confirmEmailUrl: `${
settings.siteUrl
}/user/emails/confirm?token=${token}`,
sendingUser_id: user_id
sendingUser_id: userId
}
return EmailHandler.sendEmail(emailTemplate, emailOptions, callback)
EmailHandler.sendEmail(emailTemplate, emailOptions, callback)
}
)
},
confirmEmailFromToken(token, callback) {
if (callback == null) {
callback = function(error) {}
}
logger.log(
{ token_start: token.slice(0, 8) },
'confirming email from token'
)
return OneTimeTokenHandler.getValueFromTokenAndExpire(
OneTimeTokenHandler.getValueFromTokenAndExpire(
'email_confirmation',
token,
function(error, data) {
if (error != null) {
if (error) {
return callback(error)
}
if (data == null) {
if (!data) {
return callback(new Errors.NotFoundError('no token found'))
}
const { user_id, email } = data
const userId = data.user_id
const email = data.email
logger.log(
{ data, user_id, email, token_start: token.slice(0, 8) },
{ data, userId, email, token_start: token.slice(0, 8) },
'found data for email confirmation'
)
if (user_id == null || email !== EmailHelper.parseEmail(email)) {
if (!userId || email !== EmailHelper.parseEmail(email)) {
return callback(new Errors.NotFoundError('invalid data'))
}
return UserGetter.getUser(user_id, {}, function(error, user) {
if (error != null) {
UserGetter.getUser(userId, {}, function(error, user) {
if (error) {
return callback(error)
}
if (!(user != null ? user._id : undefined)) {
if (!user) {
return callback(new Errors.NotFoundError('user not found'))
}
return UserUpdater.confirmEmail(user_id, email, callback)
UserUpdater.confirmEmail(userId, email, callback)
})
}
)
}
}
module.exports = UserEmailsConfirmationHandler

View file

@ -1,16 +1,3 @@
/* eslint-disable
handle-callback-err,
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS103: Rewrite code to no longer use __guard__
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let UserEmailsController
const AuthenticationController = require('../Authentication/AuthenticationController')
const UserGetter = require('./UserGetter')
@ -25,18 +12,18 @@ const HttpErrors = require('@overleaf/o-error/http')
module.exports = UserEmailsController = {
list(req, res, next) {
const userId = AuthenticationController.getLoggedInUserId(req)
return UserGetter.getUserFullEmails(userId, function(error, fullEmails) {
if (error != null) {
UserGetter.getUserFullEmails(userId, function(error, fullEmails) {
if (error) {
return next(error)
}
return res.json(fullEmails)
res.json(fullEmails)
})
},
add(req, res, next) {
const userId = AuthenticationController.getLoggedInUserId(req)
const email = EmailHelper.parseEmail(req.body.email)
if (email == null) {
if (!email) {
return res.sendStatus(422)
}
@ -45,47 +32,44 @@ module.exports = UserEmailsController = {
role: req.body.role,
department: req.body.department
}
return UserUpdater.addEmailAddress(
userId,
email,
affiliationOptions,
function(error) {
if (error != null) {
return UserEmailsController._handleEmailError(error, req, res, next)
}
return UserEmailsConfirmationHandler.sendConfirmationEmail(
userId,
email,
function(err) {
if (error != null) {
return next(error)
}
return res.sendStatus(204)
}
)
UserUpdater.addEmailAddress(userId, email, affiliationOptions, function(
error
) {
if (error) {
return UserEmailsController._handleEmailError(error, req, res, next)
}
)
UserEmailsConfirmationHandler.sendConfirmationEmail(
userId,
email,
function(error) {
if (error) {
return next(error)
}
res.sendStatus(204)
}
)
})
},
remove(req, res, next) {
const userId = AuthenticationController.getLoggedInUserId(req)
const email = EmailHelper.parseEmail(req.body.email)
if (email == null) {
if (!email) {
return res.sendStatus(422)
}
return UserUpdater.removeEmailAddress(userId, email, function(error) {
if (error != null) {
UserUpdater.removeEmailAddress(userId, email, function(error) {
if (error) {
return next(error)
}
return res.sendStatus(200)
res.sendStatus(200)
})
},
setDefault(req, res, next) {
const userId = AuthenticationController.getLoggedInUserId(req)
const email = EmailHelper.parseEmail(req.body.email)
if (email == null) {
if (!email) {
return res.sendStatus(422)
}
UserUpdater.setDefaultEmailAddress(userId, email, err => {
@ -100,20 +84,20 @@ module.exports = UserEmailsController = {
endorse(req, res, next) {
const userId = AuthenticationController.getLoggedInUserId(req)
const email = EmailHelper.parseEmail(req.body.email)
if (email == null) {
if (!email) {
return res.sendStatus(422)
}
return endorseAffiliation(
endorseAffiliation(
userId,
email,
req.body.role,
req.body.department,
function(error) {
if (error != null) {
if (error) {
return next(error)
}
return res.sendStatus(204)
res.sendStatus(204)
}
)
},
@ -121,43 +105,36 @@ module.exports = UserEmailsController = {
resendConfirmation(req, res, next) {
const userId = AuthenticationController.getLoggedInUserId(req)
const email = EmailHelper.parseEmail(req.body.email)
if (email == null) {
if (!email) {
return res.sendStatus(422)
}
return UserGetter.getUserByAnyEmail(email, { _id: 1 }, function(
error,
user
) {
if (error != null) {
UserGetter.getUserByAnyEmail(email, { _id: 1 }, function(error, user) {
if (error) {
return next(error)
}
if (
user == null ||
__guard__(user != null ? user._id : undefined, x => x.toString()) !==
userId
) {
if (!user || user._id.toString() !== userId) {
logger.log(
{ userId, email, foundUserId: user != null ? user._id : undefined },
{ userId, email, foundUserId: user && user._id },
"email doesn't match logged in user"
)
return res.sendStatus(422)
}
logger.log({ userId, email }, 'resending email confirmation token')
return UserEmailsConfirmationHandler.sendConfirmationEmail(
UserEmailsConfirmationHandler.sendConfirmationEmail(
userId,
email,
function(error) {
if (error != null) {
if (error) {
return next(error)
}
return res.sendStatus(200)
res.sendStatus(200)
}
)
})
},
showConfirm(req, res, next) {
return res.render('user/confirm_email', {
res.render('user/confirm_email', {
token: req.query.token,
title: 'confirm_email'
})
@ -165,23 +142,21 @@ module.exports = UserEmailsController = {
confirm(req, res, next) {
const { token } = req.body
if (token == null) {
if (!token) {
return res.sendStatus(422)
}
return UserEmailsConfirmationHandler.confirmEmailFromToken(token, function(
error
) {
if (error != null) {
UserEmailsConfirmationHandler.confirmEmailFromToken(token, function(error) {
if (error) {
if (error instanceof Errors.NotFoundError) {
return res.status(404).json({
res.status(404).json({
message:
'Sorry, your confirmation token is invalid or has expired. Please request a new email confirmation link.'
})
} else {
return next(error)
next(error)
}
} else {
return res.sendStatus(200)
res.sendStatus(200)
}
})
},
@ -207,8 +182,3 @@ module.exports = UserEmailsController = {
next(new HttpErrors.InternalServerError().withCause(error))
}
}
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
: undefined
}

View file

@ -1,16 +1,3 @@
/* eslint-disable
camelcase,
handle-callback-err,
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const mongojs = require('../../infrastructure/mongojs')
const metrics = require('metrics-sharelatex')
const logger = require('logger-sharelatex')
@ -23,10 +10,7 @@ const Features = require('../../infrastructure/Features')
const UserGetter = {
getUser(query, projection, callback) {
if (callback == null) {
callback = function(error, user) {}
}
if (query == null) {
if (!query) {
return callback(new Error('no query provided'))
}
if (arguments.length === 2) {
@ -43,24 +27,18 @@ const UserGetter = {
query = { _id: query }
}
return db.users.findOne(query, projection, callback)
db.users.findOne(query, projection, callback)
},
getUserEmail(userId, callback) {
if (callback == null) {
callback = function(error, email) {}
}
return this.getUser(userId, { email: 1 }, (error, user) =>
callback(error, user != null ? user.email : undefined)
this.getUser(userId, { email: 1 }, (error, user) =>
callback(error, user && user.email)
)
},
getUserFullEmails(userId, callback) {
if (callback == null) {
callback = function(error, emails) {}
}
return this.getUser(userId, { email: 1, emails: 1 }, function(error, user) {
if (error != null) {
this.getUser(userId, { email: 1, emails: 1 }, function(error, user) {
if (error) {
return callback(error)
}
if (!user) {
@ -71,11 +49,11 @@ const UserGetter = {
return callback(null, decorateFullEmails(user.email, user.emails, []))
}
return getUserAffiliations(userId, function(error, affiliationsData) {
if (error != null) {
getUserAffiliations(userId, function(error, affiliationsData) {
if (error) {
return callback(error)
}
return callback(
callback(
null,
decorateFullEmails(user.email, user.emails || [], affiliationsData)
)
@ -84,21 +62,15 @@ const UserGetter = {
},
getUserByMainEmail(email, projection, callback) {
if (callback == null) {
callback = function(error, user) {}
}
email = email.trim()
if (arguments.length === 2) {
callback = projection
projection = {}
}
return db.users.findOne({ email }, projection, callback)
db.users.findOne({ email }, projection, callback)
},
getUserByAnyEmail(email, projection, callback) {
if (callback == null) {
callback = function(error, user) {}
}
email = email.trim()
if (arguments.length === 2) {
callback = projection
@ -106,21 +78,18 @@ const UserGetter = {
}
// $exists: true MUST be set to use the partial index
const query = { emails: { $exists: true }, 'emails.email': email }
return db.users.findOne(query, projection, (error, user) => {
if (error != null || user != null) {
db.users.findOne(query, projection, (error, user) => {
if (error || user) {
return callback(error, user)
}
// While multiple emails are being rolled out, check for the main email as
// well
return this.getUserByMainEmail(email, projection, callback)
this.getUserByMainEmail(email, projection, callback)
})
},
getUsersByAnyConfirmedEmail(emails, projection, callback) {
if (callback == null) {
callback = function(error, user) {}
}
if (arguments.length === 2) {
callback = projection
projection = {}
@ -132,29 +101,19 @@ const UserGetter = {
$elemMatch: { email: { $in: emails }, confirmedAt: { $exists: true } }
}
}
return db.users.find(query, projection, (error, users) => {
return callback(error, users)
})
db.users.find(query, projection, callback)
},
getUsersByV1Ids(v1Ids, projection, callback) {
if (callback == null) {
callback = function(error, user) {}
}
if (arguments.length === 2) {
callback = projection
projection = {}
}
const query = { 'overleaf.id': { $in: v1Ids } }
return db.users.find(query, projection, (error, users) => {
return callback(error, users)
})
db.users.find(query, projection, callback)
},
getUsersByHostname(hostname, projection, callback) {
if (callback == null) {
callback = function(error, users) {}
}
const reversedHostname = hostname
.trim()
.split('')
@ -164,59 +123,49 @@ const UserGetter = {
emails: { $exists: true },
'emails.reversedHostname': reversedHostname
}
return db.users.find(query, projection, callback)
db.users.find(query, projection, callback)
},
getUsers(user_ids, projection, callback) {
if (callback == null) {
callback = function(error, users) {}
}
getUsers(userIds, projection, callback) {
try {
user_ids = user_ids.map(u => ObjectId(u.toString()))
} catch (error1) {
const error = error1
userIds = userIds.map(u => ObjectId(u.toString()))
} catch (error) {
return callback(error)
}
return db.users.find({ _id: { $in: user_ids } }, projection, callback)
db.users.find({ _id: { $in: userIds } }, projection, callback)
},
getUserOrUserStubById(user_id, projection, callback) {
getUserOrUserStubById(userId, projection, callback) {
let query
if (callback == null) {
callback = function(error, user, isStub) {}
}
try {
query = { _id: ObjectId(user_id.toString()) }
query = { _id: ObjectId(userId.toString()) }
} catch (e) {
return callback(new Error(e))
}
return db.users.findOne(query, projection, function(error, user) {
if (error != null) {
db.users.findOne(query, projection, function(error, user) {
if (error) {
return callback(error)
}
if (user != null) {
if (user) {
return callback(null, user, false)
}
return db.userstubs.findOne(query, projection, function(error, user) {
if (error) {
return callback(error)
db.userstubs.findOne(query, projection, function(error, user) {
if (error || user) {
return callback(error, user)
}
if (user == null) {
return callback()
}
return callback(null, user, true)
callback(null, user, true)
})
})
},
// check for duplicate email address. This is also enforced at the DB level
ensureUniqueEmailAddress(newEmail, callback) {
return this.getUserByAnyEmail(newEmail, function(error, user) {
if (user != null) {
this.getUserByAnyEmail(newEmail, function(error, user) {
if (user) {
return callback(new Errors.EmailExistsError())
}
return callback(error)
callback(error)
})
}
}
@ -228,7 +177,7 @@ var decorateFullEmails = (defaultEmail, emailsData, affiliationsData) =>
const affiliation = affiliationsData.find(
aff => aff.email === emailData.email
)
if (affiliation != null) {
if (affiliation) {
const { institution, inferred, role, department } = affiliation
emailData.affiliation = { institution, inferred, role, department }
} else {

View file

@ -1,30 +1,15 @@
/* eslint-disable
max-len,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let UserHandler
const TeamInvitesHandler = require('../Subscription/TeamInvitesHandler')
module.exports = UserHandler = {
const UserHandler = {
populateTeamInvites(user, callback) {
return TeamInvitesHandler.createTeamInvitesForLegacyInvitedEmail(
TeamInvitesHandler.createTeamInvitesForLegacyInvitedEmail(
user.email,
callback
)
},
setupLoginData(user, callback) {
if (callback == null) {
callback = function() {}
}
return this.populateTeamInvites(user, callback)
this.populateTeamInvites(user, callback)
}
}
module.exports = UserHandler

View file

@ -1,41 +1,21 @@
/* eslint-disable
camelcase,
handle-callback-err,
max-len,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let UserController
const UserGetter = require('./UserGetter')
const logger = require('logger-sharelatex')
const UserDeleter = require('./UserDeleter')
const UserUpdater = require('./UserUpdater')
const sanitize = require('sanitizer')
const AuthenticationController = require('../Authentication/AuthenticationController')
const { ObjectId } = require('mongojs')
module.exports = UserController = {
getLoggedInUsersPersonalInfo(req, res, next) {
if (next == null) {
next = function(error) {}
}
const user_id = AuthenticationController.getLoggedInUserId(req)
const userId = AuthenticationController.getLoggedInUserId(req)
logger.log(
{ user_id },
{ userId },
'reciving request for getting logged in users personal info'
)
if (user_id == null) {
if (!userId) {
return next(new Error('User is not logged in'))
}
return UserGetter.getUser(
user_id,
UserGetter.getUser(
userId,
{
first_name: true,
last_name: true,
@ -45,64 +25,55 @@ module.exports = UserController = {
signUpDate: true
},
function(error, user) {
if (error != null) {
if (error) {
return next(error)
}
return UserController.sendFormattedPersonalInfo(user, res, next)
UserController.sendFormattedPersonalInfo(user, res, next)
}
)
},
getPersonalInfo(req, res, next) {
let query
if (next == null) {
next = function(error) {}
}
const { user_id } = req.params
const userId = req.params.user_id
if (/^\d+$/.test(user_id)) {
query = { 'overleaf.id': parseInt(user_id, 10) }
} else if (/^[a-f0-9]{24}$/.test(user_id)) {
query = { _id: ObjectId(user_id) }
if (/^\d+$/.test(userId)) {
query = { 'overleaf.id': parseInt(userId, 10) }
} else if (/^[a-f0-9]{24}$/.test(userId)) {
query = { _id: ObjectId(userId) }
} else {
return res.send(400)
}
return UserGetter.getUser(
UserGetter.getUser(
query,
{ _id: true, first_name: true, last_name: true, email: true },
function(error, user) {
logger.log(
{ user_id: req.params.user_id },
{ userId },
'receiving request for getting users personal info'
)
if (error != null) {
if (error) {
return next(error)
}
if (user == null) {
if (!user) {
return res.send(404)
}
return UserController.sendFormattedPersonalInfo(user, res, next)
UserController.sendFormattedPersonalInfo(user, res, next)
}
)
},
sendFormattedPersonalInfo(user, res, next) {
if (next == null) {
next = function(error) {}
}
const info = UserController.formatPersonalInfo(user)
return res.json(info)
res.json(info)
},
formatPersonalInfo(user, callback) {
if (callback == null) {
callback = function(error, info) {}
}
if (user == null) {
if (!user) {
return {}
}
const formatted_user = { id: user._id.toString() }
const formattedUser = { id: user._id.toString() }
for (let key of [
'first_name',
'last_name',
@ -111,10 +82,10 @@ module.exports = UserController = {
'role',
'institution'
]) {
if (user[key] != null) {
formatted_user[key] = user[key]
if (user[key]) {
formattedUser[key] = user[key]
}
}
return formatted_user
return formattedUser
}
}

View file

@ -1,29 +1,13 @@
/* eslint-disable
camelcase,
handle-callback-err,
max-len,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let UserInfoManager
const UserGetter = require('./UserGetter')
module.exports = UserInfoManager = {
getPersonalInfo(user_id, callback) {
if (callback == null) {
callback = function(error) {}
}
return UserGetter.getUser(
user_id,
const UserInfoManager = {
getPersonalInfo(userId, callback) {
UserGetter.getUser(
userId,
{ _id: true, first_name: true, last_name: true, email: true },
callback
)
}
}
module.exports = UserInfoManager

View file

@ -1,18 +1,3 @@
/* eslint-disable
camelcase,
handle-callback-err,
max-len,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS103: Rewrite code to no longer use __guard__
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let UserSessionsManager
const Settings = require('settings-sharelatex')
const logger = require('logger-sharelatex')
@ -28,26 +13,23 @@ module.exports = UserSessionsManager = {
},
trackSession(user, sessionId, callback) {
if (callback == null) {
callback = function(err) {}
}
if (user == null) {
if (!user) {
logger.log({ sessionId }, 'no user to track, returning')
return callback(null)
}
if (sessionId == 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')
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
const value = UserSessionsManager._sessionKey(sessionId)
return rclient
rclient
.multi()
.sadd(sessionSetKey, value)
.pexpire(sessionSetKey, `${Settings.cookieSessionLength}`) // in milliseconds
.exec(function(err, response) {
if (err != null) {
if (err) {
logger.warn(
{ err, user_id: user._id, sessionSetKey },
'error while adding session key to UserSessions set'
@ -55,31 +37,31 @@ module.exports = UserSessionsManager = {
return callback(err)
}
UserSessionsManager._checkSessions(user, function() {})
return callback()
callback()
})
},
untrackSession(user, sessionId, callback) {
if (callback == null) {
callback = function(err) {}
if (!callback) {
callback = function() {}
}
if (user == null) {
if (!user) {
logger.log({ sessionId }, 'no user to untrack, returning')
return callback(null)
}
if (sessionId == 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')
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
const value = UserSessionsManager._sessionKey(sessionId)
return rclient
rclient
.multi()
.srem(sessionSetKey, value)
.pexpire(sessionSetKey, `${Settings.cookieSessionLength}`) // in milliseconds
.exec(function(err, response) {
if (err != null) {
if (err) {
logger.warn(
{ err, user_id: user._id, sessionSetKey },
'error while removing session key from UserSessions set'
@ -87,18 +69,15 @@ module.exports = UserSessionsManager = {
return callback(err)
}
UserSessionsManager._checkSessions(user, function() {})
return callback()
callback()
})
},
getAllUserSessions(user, exclude, callback) {
if (callback == null) {
callback = function(err, sessionKeys) {}
}
exclude = _.map(exclude, UserSessionsManager._sessionKey)
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
return rclient.smembers(sessionSetKey, function(err, sessionKeys) {
if (err != null) {
rclient.smembers(sessionSetKey, function(err, sessionKeys) {
if (err) {
logger.warn(
{ user_id: user._id },
'error getting all session keys for user from redis'
@ -111,58 +90,53 @@ module.exports = UserSessionsManager = {
return callback(null, [])
}
return Async.mapSeries(
sessionKeys,
(k, cb) => rclient.get(k, cb),
function(err, sessions) {
if (err != null) {
logger.warn(
{ user_id: user._id },
'error getting all sessions for user from redis'
)
return callback(err)
}
const result = []
for (let session of Array.from(sessions)) {
if (session === null) {
continue
}
session = JSON.parse(session)
const session_user =
(session != null ? session.user : undefined) ||
__guard__(
session != null ? session.passport : undefined,
x => x.user
)
result.push({
ip_address: session_user.ip_address,
session_created: session_user.session_created
})
}
return callback(null, result)
Async.mapSeries(sessionKeys, (k, cb) => rclient.get(k, cb), function(
err,
sessions
) {
if (err) {
logger.warn(
{ user_id: user._id },
'error getting all sessions for user from redis'
)
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 (callback == null) {
callback = function(err) {}
}
if (retain == null) {
if (!retain) {
retain = []
}
retain = retain.map(i => UserSessionsManager._sessionKey(i))
if (user == null) {
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')
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
return rclient.smembers(sessionSetKey, function(err, sessionKeys) {
if (err != null) {
rclient.smembers(sessionSetKey, function(err, sessionKeys) {
if (err) {
logger.warn(
{ err, user_id: user._id, sessionSetKey },
'error getting contents of UserSessions set'
@ -187,65 +161,59 @@ module.exports = UserSessionsManager = {
const deletions = keysToDelete.map(k => cb => rclient.del(k, cb))
return Async.series(deletions, function(err, _result) {
if (err != null) {
Async.series(deletions, function(err, _result) {
if (err) {
logger.warn(
{ err, user_id: user._id, sessionSetKey },
'errror revoking all sessions for user'
)
return callback(err)
}
return rclient.srem(sessionSetKey, keysToDelete, function(err) {
if (err != null) {
rclient.srem(sessionSetKey, keysToDelete, function(err) {
if (err) {
logger.warn(
{ err, user_id: user._id, sessionSetKey },
'error removing session set for user'
)
return callback(err)
}
return callback(null)
callback(null)
})
})
})
},
touch(user, callback) {
if (callback == null) {
callback = function(err) {}
}
if (user == null) {
if (!user) {
logger.log({}, 'no user to touch sessions for, returning')
return callback(null)
}
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
return rclient.pexpire(
rclient.pexpire(
sessionSetKey,
`${Settings.cookieSessionLength}`, // in milliseconds
function(err, response) {
if (err != null) {
if (err) {
logger.warn(
{ err, user_id: user._id },
'error while updating ttl on UserSessions set'
)
return callback(err)
}
return callback(null)
callback(null)
}
)
},
_checkSessions(user, callback) {
if (callback == null) {
callback = function(err) {}
}
if (user == null) {
if (!user) {
logger.log({}, 'no user, returning')
return callback(null)
}
logger.log({ user_id: user._id }, 'checking sessions for user')
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
return rclient.smembers(sessionSetKey, function(err, sessionKeys) {
if (err != null) {
rclient.smembers(sessionSetKey, function(err, sessionKeys) {
if (err) {
logger.warn(
{ err, user_id: user._id, sessionSetKey },
'error getting contents of UserSessions set'
@ -256,39 +224,30 @@ module.exports = UserSessionsManager = {
{ user_id: user._id, count: sessionKeys.length },
'checking sessions for user'
)
return Async.series(
Async.series(
sessionKeys.map(key => next =>
rclient.get(key, function(err, val) {
if (err != null) {
if (err) {
return next(err)
}
if (val == null) {
if (!val) {
logger.log(
{ user_id: user._id, key },
'>> removing key from UserSessions set'
)
return rclient.srem(sessionSetKey, key, function(err, result) {
if (err != null) {
return next(err)
}
return next(null)
rclient.srem(sessionSetKey, key, function(err, result) {
return next(err)
})
} else {
return next()
next()
}
})
),
function(err, results) {
logger.log({ user_id: user._id }, 'done checking sessions for user')
return callback(err)
callback(err)
}
)
})
}
}
function __guard__(value, transform) {
return typeof value !== 'undefined' && value !== null
? transform(value)
: undefined
}

View file

@ -1,13 +1,7 @@
/* eslint-disable
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
let Redis
const RedisWrapper = require('../../infrastructure/RedisWrapper')
const rclient = RedisWrapper.client('websessions')
module.exports = Redis = {
const UserSessionsRedis = {
client() {
return rclient
},
@ -16,3 +10,4 @@ module.exports = Redis = {
return `UserSessions:{${user._id}}`
}
}
module.exports = UserSessionsRedis