let XDate = require('xdate') let cookie = require('cookie') let crypto = require('crypto') return async (env, transaction) => { let cookies = cookie.parse(env.request.headers.cookie || '') let now = Date.now() let sessions = await ( await transaction.get({}) ).get('sessions', {}) let session_key, session, expires = new XDate(now) if ( Object.prototype.hasOwnProperty.call(cookies, 'session_key') && ( session = await sessions.get(session_key = cookies.session_key) ) !== undefined && now < await session.get('expires', 0) ) // if session key is already in database, we know the requester supports // cookies, therefore each access extends the session expiry by 1 month expires.addMonths(1) else { // first request for session, maybe a bot, retain session for only 1 day expires.addDays(1) do { session_key = crypto.randomBytes(16).toString('hex') } while (sessions.has(session_key)) session = transaction.LazyObject() sessions.set(session_key, session) } await session.set('expires', expires.getTime()) env.response.setHeader( 'Set-Cookie', `session_key=${session_key}; expires=${expires.toUTCString()}; path=/;` ) env.session_key = session_key return session }