@ -3,34 +3,51 @@ const { v4: uuidv4 } = require("uuid")
const { logWarn } = require ( "../logging" )
const env = require ( "../environment" )
interface Session {
key : string
userId : string
sessionId : string
lastAccessedAt : string
createdAt : string
csrfToken? : string
value : string
}
type SessionKey = { key : string } [ ]
// a week in seconds
const EXPIRY_SECONDS = 86400 * 7
async function getSessionsForUser ( userId ) {
const client = await redis . getSessionClient ( )
const sessions = await client . scan ( userId )
return sessions . map ( session = > session . value )
function makeSessionID ( userId : string , sessionId : string ) {
return ` ${ userId } / ${ sessionId } `
}
function makeSessionID ( userId , sessionId ) {
return ` ${ userId } / ${ sessionId } `
export async function getSessionsForUser ( userId : string ) {
const client = await redis . getSessionClient ( )
const sessions = await client . scan ( userId )
return sessions . map ( ( session : Session ) = > session . value )
}
async function invalidateSessions ( userId , sessionIds = null ) {
export async function invalidateSessions (
userId : string ,
opts : { sessionIds? : string [ ] ; reason? : string } = { }
) {
try {
let sessions = [ ]
const reason = opts ? . reason || "unknown"
let sessionIds : string [ ] = opts . sessionIds || [ ]
let sessions : SessionKey
// If no sessionIds, get all the sessions for the user
if ( ! sessionIds ) {
sessions = await getSessionsForUser ( userId )
sessions . forEach (
session = >
( session : any ) = >
( session . key = makeSessionID ( session . userId , session . sessionId ) )
)
} else {
// use the passed array of sessionIds
sessions = Array . isArray ( sessionIds ) ? sessionIds : [ sessionIds ]
sessions = sessions . map ( sessionId = > ( {
sessionId s = Array . isArray ( sessionIds ) ? sessionIds : [ sessionIds ]
sessions = sessionId s . map ( ( sessionId : string ) = > ( {
key : makeSessionID ( userId , sessionId ) ,
} ) )
}
@ -43,7 +60,7 @@ async function invalidateSessions(userId, sessionIds = null) {
}
if ( ! env . isTest ( ) ) {
logWarn (
` Invalidating sessions for ${ userId } - ${ sessions
` Invalidating sessions for ${ userId } (reason: ${ reason } ) - ${ sessions
. map ( session = > session . key )
. join ( ", " ) } `
)
@ -55,9 +72,9 @@ async function invalidateSessions(userId, sessionIds = null) {
}
}
exports . createASession = async ( userId , session ) = > {
export async function createASession ( userId : string , session : Session ) {
// invalidate all other sessions
await invalidateSessions ( userId )
await invalidateSessions ( userId , { reason : "creation" } )
const client = await redis . getSessionClient ( )
const sessionId = session . sessionId
@ -65,27 +82,27 @@ exports.createASession = async (userId, session) => {
session . csrfToken = uuidv4 ( )
}
session = {
. . . session ,
createdAt : new Date ( ) . toISOString ( ) ,
lastAccessedAt : new Date ( ) . toISOString ( ) ,
. . . session ,
userId ,
}
await client . store ( makeSessionID ( userId , sessionId ) , session , EXPIRY_SECONDS )
}
exports . updateSessionTTL = async session = > {
export async function updateSessionTTL ( session : Session ) {
const client = await redis . getSessionClient ( )
const key = makeSessionID ( session . userId , session . sessionId )
session . lastAccessedAt = new Date ( ) . toISOString ( )
await client . store ( key , session , EXPIRY_SECONDS )
}
exports . endSession = async ( userId , sessionId ) = > {
export async function endSession ( userId : string , sessionId : string ) {
const client = await redis . getSessionClient ( )
await client . delete ( makeSessionID ( userId , sessionId ) )
}
exports . getSession = async ( userId , sessionId ) = > {
export async function getSession ( userId : string , sessionId : string ) {
try {
const client = await redis . getSessionClient ( )
return client . get ( makeSessionID ( userId , sessionId ) )
@ -96,11 +113,8 @@ exports.getSession = async (userId, sessionId) => {
}
}
exports . getAllSessions = async ( ) = > {
export async function getAllSessions() {
const client = await redis . getSessionClient ( )
const sessions = await client . scan ( )
return sessions . map ( session = > session . value )
return sessions . map ( ( session : Session ) = > session . value )
}
exports . getUserSessions = getSessionsForUser
exports . invalidateSessions = invalidateSessions