Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support to dynamic cookie options generation #1027

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,26 @@ For a list of stores, see [compatible session stores](#compatible-session-stores
Settings object for the session ID cookie. The default value is
`{ path: '/', httpOnly: true, secure: false, maxAge: null }`.

In addition to providing a static object, you can also pass a callback function to dynamically generate the cookie options for each request. The callback receives the `req` object as its argument and should return an object containing the cookie settings.

```js
var app = express()
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: function(req) {
var match = req.url.match(/^\/([^/]+)/);
return {
path: match ? '/' + match[1] : '/',
httpOnly: true,
secure: req.secure || false,
maxAge: 60000
}
}
}))
```

The following are options that can be set in this object.

##### cookie.domain
Expand Down
7 changes: 4 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ var defer = typeof setImmediate === 'function'
* Setup session store with the given `options`.
*
* @param {Object} [options]
* @param {Object} [options.cookie] Options for cookie
* @param {Object|Function} [options.cookie] Options for cookie
* @param {Function} [options.genid]
* @param {String} [options.name=connect.sid] Session ID cookie name
* @param {Boolean} [options.proxy]
Expand Down Expand Up @@ -158,7 +158,7 @@ function session(options) {
store.generate = function(req){
req.sessionID = generateId(req);
req.session = new Session(req);
req.session.cookie = new Cookie(cookieOptions);
req.session.cookie = new Cookie(typeof cookieOptions === 'function' ? cookieOptions(req) : cookieOptions);

if (cookieOptions.secure === 'auto') {
req.session.cookie.secure = issecure(req, trustProxy);
Expand Down Expand Up @@ -193,7 +193,8 @@ function session(options) {

// pathname mismatch
var originalPath = parseUrl.original(req).pathname || '/'
if (originalPath.indexOf(cookieOptions.path || '/') !== 0) {
var resolvedCookieOptions = typeof cookieOptions === 'function' ? cookieOptions(req) : cookieOptions
if (originalPath.indexOf(resolvedCookieOptions.path || '/') !== 0) {
debug('pathname mismatch')
next()
return
Expand Down
53 changes: 53 additions & 0 deletions test/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,59 @@ describe('session()', function(){
})
})
})

describe('when "cookie" is a function', function () {
it('should call custom function and apply cookie options', function (done) {
var cookieCallbackCalled = false;
var cookieCallback = function () {
cookieCallbackCalled = true;
return { path: '/test', httpOnly: true, secure: false };
};
var server = createServer({ cookie: cookieCallback });
request(server)
.get('/test')
.expect(
shouldSetCookieWithAttributeAndValue('connect.sid', 'Path', '/test')
)
.expect(shouldSetCookieWithAttribute('connect.sid', 'HttpOnly'))
.expect(shouldSetCookieWithoutAttribute('connect.sid', 'Secure'))
.expect(200, function (err) {
if (err) return done(err);
assert.strictEqual(
cookieCallbackCalled,
true,
'should have called cookie callback'
);
done();
});
});

it('should provide req argument', function (done) {
var _path = '/test';
var cookieCallbackCalled = false;
var cookieCallback = function (req) {
cookieCallbackCalled = true;
return { path: req.url, httpOnly: true, secure: false };
};
var server = createServer({ cookie: cookieCallback });
request(server)
.get(_path)
.expect(
shouldSetCookieWithAttributeAndValue('connect.sid', 'Path', _path)
)
.expect(shouldSetCookieWithAttribute('connect.sid', 'HttpOnly'))
.expect(shouldSetCookieWithoutAttribute('connect.sid', 'Secure'))
.expect(200, function (err) {
if (err) return done(err);
assert.strictEqual(
cookieCallbackCalled,
true,
'should have called cookie callback'
);
done();
});
});
});
})

describe('genid option', function(){
Expand Down