3 * Connect - cookieSession
4 * Copyright(c) 2011 Sencha Inc.
12 var utils = require('./../utils')
13 , Cookie = require('./session/cookie')
14 , debug = require('debug')('connect:cookieSession')
15 , crc16 = require('crc').crc16;
19 var env = process.env.NODE_ENV;
24 * Cookie session middleware.
26 * var app = connect();
27 * app.use(connect.cookieParser());
28 * app.use(connect.cookieSession({ secret: 'tobo!', cookie: { maxAge: 60 * 60 * 1000 }}));
32 * - `key` cookie name defaulting to `connect.sess`
33 * - `secret` prevents cookie tampering
34 * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
35 * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
39 * To clear the session simply set its value to `null`,
40 * `cookieSession()` will then respond with a 1970 Set-Cookie.
44 * @param {Object} options
49 module.exports = function cookieSession(options){
50 // TODO: utilize Session/Cookie to unify API
51 var options = options || {}
52 , key = options.key || 'connect.sess'
53 , trustProxy = options.proxy;
55 return function cookieSession(req, res, next) {
57 // req.secret is for backwards compatibility
58 var secret = options.secret || req.secret;
59 if (!secret) throw new Error('`secret` option required for cookie sessions');
63 var cookie = req.session.cookie = new Cookie(options.cookie);
66 if (0 != req.originalUrl.indexOf(cookie.path)) return next();
68 // cookieParser secret
69 if (!options.secret && req.secret) {
70 req.session = req.signedCookies[key] || {};
73 var rawCookie = req.cookies[key];
75 var unsigned = utils.parseSignedCookie(rawCookie, secret);
77 var originalHash = crc16(unsigned);
78 req.session = utils.parseJSONCookie(unsigned) || {};
83 res.on('header', function(){
86 debug('clear session');
87 cookie.expires = new Date(0);
88 res.setHeader('Set-Cookie', cookie.serialize(key, ''));
92 delete req.session.cookie;
95 var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()
96 , tls = req.connection.encrypted || (trustProxy && 'https' == proto)
97 , secured = cookie.secure && tls;
99 // only send secure cookies via https
100 if (cookie.secure && !secured) return debug('not secured');
103 debug('serializing %j', req.session);
104 var val = 'j:' + JSON.stringify(req.session);
106 // compare hashes, no need to set-cookie if unchanged
107 if (originalHash == crc16(val)) return debug('unmodified session');
110 val = 's:' + utils.sign(val, secret);
111 val = cookie.serialize(key, val);
112 debug('set-cookie %j', cookie);
113 res.setHeader('Set-Cookie', val);