/// import {Request, Response, RequestHandler} from 'express'; import RedisSessionsAnywhere, {SessionObject, TokenGenerator, TokenAndClientToken, ClientToken, ConnectOptions} from '../'; let debug = require('debug')('resa:Connect'); export default function connect(sessions: RedisSessionsAnywhere, generator: TokenGenerator, options?: ConnectOptions): RequestHandler { options = merge({ cookieName: 'resa', alwaysUpdate: false, sessionKey: 'session' }, options); return (request: Request, response: Response, next: Function) => { let clientToken: string; let token: string; let generated = false; let previousEnd = (response as any)._storeHeader; let originalSession; (response as any)._storeHeader = function() { // todo check if session data changed let shouldUpdate: boolean = options.alwaysUpdate || generated; if (!shouldUpdate) { // we can do better, but for now this is a good json check shouldUpdate = JSON.stringify(originalSession) !== JSON.stringify(request[options.sessionKey]); } let instance = response; if (!shouldUpdate) { return finishUp(arguments, instance); } delete request[options.sessionKey]._token; // we don't need this now if (options.alwaysUpdate) { clientToken = generator.generateClientToken(token); setCookie(); } finishUp(arguments, instance); sessions.set(token, request[options.sessionKey]).catch(debug); }; if (request.signedCookies[options.cookieName]) { clientToken = request.signedCookies[options.cookieName]; let parsed: ClientToken; try { parsed = generator.parseClientToken(clientToken); } catch (err) { debug('Error parsing token', err); return next(new Error('Invalid token')); } if (!generator.isValid(parsed)) { return next(new Error('Token has expired')); } token = parsed.token; return update(); } // no token, let's generate one generator.generateKey().then((key: TokenAndClientToken) => { token = key.token; clientToken = key.clientToken; generated = true; setCookie(); update(); }); function update() { sessions.get(token).then((session: SessionObject) => { let data = session ? session.data : {}; data._token = token; request[options.sessionKey] = data; originalSession = merge({}, data); next(); // we're done here, until the request is finished }); } function finishUp(args: any, instance: any) { previousEnd.apply(instance, args); } function setCookie() { response.cookie(options.cookieName, clientToken, {signed: true, maxAge: sessions.options.ttl}); } }; }; function merge(original: T, object: any): T { if (object) { for (let property in object) { original[property] = object[property]; } } return original; }