express-session
Advanced tools
Comparing version 1.3.1 to 1.4.0
@@ -0,1 +1,10 @@ | ||
1.4.0 / 2014-06-17 | ||
================== | ||
* Add `genid` option to generate custom session IDs | ||
* Add `saveUninitialized` option to control saving uninitialized sessions | ||
* Add `unset` option to control unsetting `req.session` | ||
* Generate session IDs with `rand-token` by default; reduce collisions | ||
* deps: buffer-crc32@0.2.3 | ||
1.3.1 / 2014-06-14 | ||
@@ -2,0 +11,0 @@ ================== |
97
index.js
@@ -12,3 +12,3 @@ /*! | ||
var uid = require('uid2') | ||
var uid = require('rand-token').suid | ||
, onHeaders = require('on-headers') | ||
@@ -76,2 +76,8 @@ , crc32 = require('buffer-crc32') | ||
var generateId = options.genid || generateSessionId; | ||
if (typeof generateId !== 'function') { | ||
throw new TypeError('genid option must be a function'); | ||
} | ||
// TODO: switch default to false on next major | ||
@@ -82,2 +88,13 @@ var resaveSession = options.resave === undefined | ||
var saveUninitializedSession = options.saveUninitialized === undefined | ||
? true | ||
: options.saveUninitialized; | ||
if (options.unset && options.unset !== 'destroy' && options.unset !== 'keep') { | ||
throw new TypeError('unset option must be "destroy" or "keep"'); | ||
} | ||
// TODO: switch to "destroy" on next major | ||
var unsetDestroy = options.unset === 'destroy'; | ||
// notify user that this store is not | ||
@@ -91,3 +108,3 @@ // meant for a production environment | ||
store.generate = function(req){ | ||
req.sessionID = uid(24); | ||
req.sessionID = generateId(req); | ||
req.session = new Session(req); | ||
@@ -152,19 +169,4 @@ req.session.cookie = new Cookie(cookie); | ||
var isNew = unsignedCookie != req.sessionID; | ||
// in case of rolling session, always reset the cookie | ||
if (!rollingSessions) { | ||
// browser-session length cookie | ||
if (null == cookie.expires) { | ||
if (!isNew) { | ||
debug('already set browser-session cookie'); | ||
return | ||
} | ||
// compare hashes and ids | ||
} else if (!isModified(req.session)) { | ||
debug('unmodified session'); | ||
return | ||
} | ||
if (!shouldSetCookie(req)) { | ||
return; | ||
} | ||
@@ -181,6 +183,22 @@ | ||
res.end = end; | ||
if (!req.session) return res.end(data, encoding); | ||
if (shouldDestroy(req)) { | ||
// destroy session | ||
debug('destroying'); | ||
store.destroy(req.sessionID, function(err){ | ||
if (err) console.error(err.stack); | ||
debug('destroyed'); | ||
res.end(data, encoding); | ||
}); | ||
} | ||
// no session to save | ||
if (!req.session) { | ||
debug('no session'); | ||
return res.end(data, encoding); | ||
} | ||
req.session.resetMaxAge(); | ||
if (resaveSession || isModified(req.session)) { | ||
if (shouldSave(req)) { | ||
debug('saving'); | ||
@@ -200,2 +218,4 @@ return req.session.save(function(err){ | ||
store.generate(req); | ||
originalId = req.sessionID; | ||
originalHash = hash(req.session); | ||
} | ||
@@ -208,2 +228,26 @@ | ||
// determine if session should be destroyed | ||
function shouldDestroy(req) { | ||
return req.sessionID && unsetDestroy && req.session == null; | ||
} | ||
// determine if session should be saved to store | ||
function shouldSave(req) { | ||
return unsignedCookie != req.sessionID | ||
? saveUninitializedSession || isModified(req.session) | ||
: resaveSession || isModified(req.session); | ||
} | ||
// determine if cookie should be set on response | ||
function shouldSetCookie(req) { | ||
// in case of rolling session, always reset the cookie | ||
if (rollingSessions) { | ||
return true; | ||
} | ||
return unsignedCookie != req.sessionID | ||
? saveUninitializedSession || isModified(req.session) | ||
: req.session.cookie.expires != null && isModified(req.session); | ||
} | ||
// get the sessionID from the cookie | ||
@@ -250,2 +294,13 @@ req.sessionID = unsignedCookie; | ||
/** | ||
* Generate a session ID for a new session. | ||
* | ||
* @return {String} | ||
* @api private | ||
*/ | ||
function generateSessionId(sess) { | ||
return uid(24); | ||
} | ||
/** | ||
* Hash the given `sess` object omitting changes to `.cookie`. | ||
@@ -252,0 +307,0 @@ * |
{ | ||
"name": "express-session", | ||
"version": "1.3.1", | ||
"version": "1.4.0", | ||
"description": "Simple session middleware for Express", | ||
"author": "TJ Holowaychuk <tj@vision-media.ca> (http://tjholowaychuk.com)", | ||
"contributors": [ | ||
"Douglas Christopher Wilson <doug@somethingdoug.com>", | ||
"Joe Wagner <njwjs722@gmail.com>" | ||
], | ||
"repository": "expressjs/session", | ||
"license": "MIT", | ||
"dependencies": { | ||
"buffer-crc32": "0.2.1", | ||
"buffer-crc32": "0.2.3", | ||
"cookie": "0.1.2", | ||
@@ -14,3 +18,3 @@ "cookie-signature": "1.0.3", | ||
"on-headers": "0.0.0", | ||
"uid2": "0.0.3", | ||
"rand-token": "0.2.1", | ||
"utils-merge": "1.0.0" | ||
@@ -17,0 +21,0 @@ }, |
@@ -5,2 +5,3 @@ # express-session | ||
[![Build Status](https://travis-ci.org/expressjs/session.svg?branch=master)](https://travis-ci.org/expressjs/session) | ||
[![Coverage Status](https://img.shields.io/coveralls/expressjs/session.svg?branch=master)](https://coveralls.io/r/expressjs/session) | ||
@@ -38,7 +39,24 @@ THIS REPOSITORY NEEDS A MAINTAINER. IF YOU'RE INTERESTED IN MAINTAINING THIS REPOSITORY, PLEASE LET US KNOW! | ||
- (default: `{ path: '/', httpOnly: true, secure: false, maxAge: null }`) | ||
- `genid` - function to call to generate a new session ID. (default: uses `uid2` library) | ||
- `rolling` - forces a cookie set on every response. This resets the expiration date. (default: `false`) | ||
- `resave` - forces session to be saved even when unmodified. (default: `true`) | ||
- `proxy` - trust the reverse proxy when setting secure cookies (via "x-forwarded-proto" header). When set to `true`, the "x-forwarded-proto" header will be used. When set to `false`, all headers are ignored. When left unset, will use the "trust proxy" setting from express. (default: `undefined`) | ||
- `saveUninitialized` - forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified. This is useful for implementing login sessions, reducing server storage usage, or complying with laws that require permission before setting a cookie. (default: `true`) | ||
- `unset` - controls result of unsetting `req.session` (through `delete`, setting to `null`, etc.). This can be "keep" to keep the session in the store but ignore modifications or "destroy" to destroy the stored session. (default: `'keep'`) | ||
#### options.genid | ||
Generate a custom session ID for new sessions. Provide a function that returns a string that will be used as a session ID. The function is given `req` as the first argument if you want to use some value attached to `req` when generating the ID. | ||
**NOTE** be careful you generate unique IDs so your sessions do not conflict. | ||
```js | ||
app.use(session({ | ||
genid: function(req) { | ||
return genuuid(); // use UUIDs for session IDs | ||
}, | ||
secret: 'keyboard cat' | ||
})) | ||
``` | ||
#### Cookie options | ||
@@ -45,0 +63,0 @@ |
@@ -19,5 +19,6 @@ | ||
var asyncTick = typeof setImmediate === 'function' | ||
/* istanbul ignore next */ | ||
var defer = typeof setImmediate === 'function' | ||
? setImmediate | ||
: process.nextTick; | ||
: function(fn){ process.nextTick(fn.bind.apply(fn, arguments)) } | ||
@@ -50,19 +51,21 @@ /** | ||
var self = this; | ||
asyncTick(function(){ | ||
var expires | ||
, sess = self.sessions[sid]; | ||
if (sess) { | ||
sess = JSON.parse(sess); | ||
expires = 'string' == typeof sess.cookie.expires | ||
? new Date(sess.cookie.expires) | ||
: sess.cookie.expires; | ||
if (!expires || new Date < expires) { | ||
fn(null, sess); | ||
} else { | ||
self.destroy(sid, fn); | ||
} | ||
} else { | ||
fn(); | ||
} | ||
}); | ||
var sess = self.sessions[sid]; | ||
if (!sess) { | ||
return defer(fn); | ||
} | ||
// parse | ||
sess = JSON.parse(sess); | ||
var expires = typeof sess.cookie.expires === 'string' | ||
? new Date(sess.cookie.expires) | ||
: sess.cookie.expires; | ||
// destroy expired session | ||
if (expires && expires <= Date.now()) { | ||
return self.destroy(sid, fn); | ||
} | ||
defer(fn, null, sess); | ||
}; | ||
@@ -80,7 +83,4 @@ | ||
MemoryStore.prototype.set = function(sid, sess, fn){ | ||
var self = this; | ||
asyncTick(function(){ | ||
self.sessions[sid] = JSON.stringify(sess); | ||
fn && fn(); | ||
}); | ||
this.sessions[sid] = JSON.stringify(sess); | ||
fn && defer(fn); | ||
}; | ||
@@ -96,7 +96,4 @@ | ||
MemoryStore.prototype.destroy = function(sid, fn){ | ||
var self = this; | ||
asyncTick(function(){ | ||
delete self.sessions[sid]; | ||
fn && fn(); | ||
}); | ||
delete this.sessions[sid]; | ||
fn && defer(fn); | ||
}; | ||
@@ -117,3 +114,3 @@ | ||
} | ||
fn(null, arr); | ||
fn && defer(fn); | ||
}; | ||
@@ -130,3 +127,3 @@ | ||
this.sessions = {}; | ||
fn && fn(); | ||
fn && defer(fn); | ||
}; | ||
@@ -142,3 +139,4 @@ | ||
MemoryStore.prototype.length = function(fn){ | ||
fn(null, Object.keys(this.sessions).length); | ||
var len = Object.keys(this.sessions).length; | ||
defer(fn, null, len); | ||
}; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
27915
670
209
+ Addedrand-token@0.2.1
+ Addedbuffer-crc32@0.2.3(transitive)
+ Addedrand-token@0.2.1(transitive)
- Removeduid2@0.0.3
- Removedbuffer-crc32@0.2.1(transitive)
- Removeduid2@0.0.3(transitive)
Updatedbuffer-crc32@0.2.3