From fae31689b1df78ca7ff2eea5c296eca734dca542 Mon Sep 17 00:00:00 2001 From: why Date: Thu, 18 Jun 2015 14:27:08 +0800 Subject: [PATCH 1/3] options add 'nextopen' item --- README.md | 19 +++++++++ index.js | 20 ++++++++++ test/session.js | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) diff --git a/README.md b/README.md index 10d2f49d..85f2b2d3 100644 --- a/README.md +++ b/README.md @@ -280,6 +280,25 @@ The default value is `'keep'`. - `'keep'` The session in the store will be kept, but modifications made during the request are ignored and not saved. +##### nextopen +Close the browser to save the session, of course, you must configure the expiration time for the sessionID. + +The default value is `true`. + + - `false` cookie.maxAge is any, User closes the browser sessionID reset; + +For example,The following Settings. The user if not close the browser for more than 20 minutes, the session will also be reset. + +```js +var app = express() +app.set('trust proxy', 1) // trust first proxy +app.use(session({ + secret: 'keyboard cat', + cookie: { maxAge: 60000 * 20} + nextopen: false +})) +``` + ### req.session To store or access session data, simply use the request property `req.session`, diff --git a/index.js b/index.js index 68ccf533..5005e57c 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ var crc = require('crc').crc32; var debug = require('debug')('express-session'); var deprecate = require('depd')('express-session'); var parseUrl = require('parseurl'); +var querystring = require('querystring'); var uid = require('uid-safe').sync , onHeaders = require('on-headers') , signature = require('cookie-signature') @@ -79,6 +80,7 @@ var defer = typeof setImmediate === 'function' * @param {String|Array} [options.secret] Secret for signing session ID * @param {Object} [options.store=MemoryStore] Session store * @param {String} [options.unset] + * @param {String} [options.nextopen] Whether save session at the next open browser。 * @return {Function} middleware * @public */ @@ -113,6 +115,14 @@ function session(options) { // get the cookie signing secret var secret = opts.secret + // get onoff nextopen + var nextopen = options.nextopen === undefined ? true : options.nextopen + var sessionID_Dep; + + if(!nextopen && (cookieOptions.maxAge || cookieOptions.expires) && (new Cookie(cookieOptions)).expires > Date.now()){ + sessionID_Dep = name + '.dep'; + } + if (typeof generateId !== 'function') { throw new TypeError('genid option must be a function'); } @@ -176,6 +186,16 @@ function session(options) { }) return function session(req, res, next) { + // Processing reopen the browser session + if(sessionID_Dep){ + if(!req.cookies[sessionID_Dep]){ + delete req.cookies[name] + req.headers.cookie = querystring.stringify(req.cookies, ';', '=') + //res.cookie(sessionID_Dep,'Dep',{httpOnly:true}) + setcookie(res, sessionID_Dep, "Dep", "Dep", {httpOnly:true}); + } + } + // self-awareness if (req.session) { next() diff --git a/test/session.js b/test/session.js index e0c97d60..e259c78d 100644 --- a/test/session.js +++ b/test/session.js @@ -888,6 +888,108 @@ describe('session()', function(){ }); }); + describe('nextopen option', function(){ + it('should default to true',function(done){ + var app = express(),mark = 0; + app.use(cookieParser()); + app.use(session({ secret: 'keyboard cat', cookie: { maxAge: min }})); + app.use(function(req, res, next){ + var save = req.session.save; + if(!mark){ + mark = req.session.user = 'bob'; + } + res.setHeader("test-user",req.session.user || 'undefined') + res.end(); + }); + request(app) + .get('/') + .expect('test-user','bob') + .expect(200, function(err, res){ + if (err) return done(err); + request(app) + .get('/') + .set('Cookie', cookie(res)) + .expect('test-user','bob') + .expect(200,done) + }); + }) + it('Clear no expiration time "cookie" (analog browser is closed) session loss',function(done){ + var app = express(),mark=0; + app.use(cookieParser()); + app.use(session({nextopen: false, secret: 'keyboard cat', cookie: { maxAge: min }})); + app.use(function(req, res, next){ + var save = req.session.save; + if(!mark){ + mark = req.session.user = 'bob'; + } + res.setHeader("test-user",req.session.user || 'undefined') + res.end(); + }); + request(app) + .get('/') + .expect('test-user','bob') + .expect(function(res){ + var cookies = res.headers['set-cookie'] + for(var i in cookies){ + var v = cookies[i] + if(v.indexOf('connect.sid.dep') === 0) return; + } + return new Error('nextopen not working'); + }) + .expect(200, function(err, res){ + if (err) return done(err); + var cookies = res.headers['set-cookie'] + for(var i = 0; i < cookies.length; i++){ + var v = cookies[i]; + if(v.indexOf('Expires=') == -1){ + cookies.splice(i,1); + i--; + }else{ + cookies[i] = v.split(';')[0] + } + } + request(app) + .get('/') + .set('Cookie', cookies.join(';')) + .expect(function(res){ + if(res.headers['test-user'] == "bob") return Error ('Clear session failed'); + }) + .expect(200,done) + }); + }) + it('maxAge is null, not take effect then "false"',function(done){ + var app = express(),mark=0; + app.use(session({nextopen:false, secret: 'keyboard cat', cookie: { maxAge: null }})); + app.use(function(req, res, next){ + var save = req.session.save; + if(!mark){ + mark = req.session.user = 'bob'; + } + res.setHeader("test-user",req.session.user || 'undefined') + res.end(); + }); + request(app) + .get('/') + .expect('test-user','bob') + .expect(function(res){ + var cookies = res.headers['set-cookie'] + for(var i in cookies){ + var v = cookies[i] + assert.ok(v.indexOf('connect.sid.dep') !== 0,'nextopen Working Error') + } + }) + .expect(200, function(err, res){ + if (err) return done(err); + console.log(res.body) + request(app) + .get('/') + .set('Cookie', cookie(res)) + .expect('test-user','bob') + .expect(200,done) + }); + }) + }); + describe('resave option', function(){ it('should default to true', function(done){ var store = new session.MemoryStore() From c8bc19b8635676972fd54f102e73d01f7de480e4 Mon Sep 17 00:00:00 2001 From: why Date: Thu, 18 Jun 2015 14:27:08 +0800 Subject: [PATCH 2/3] options add 'nextopen' item --- README.md | 19 +++++++++ index.js | 20 ++++++++++ test/session.js | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) diff --git a/README.md b/README.md index a2b96bcd..7e04e7b3 100644 --- a/README.md +++ b/README.md @@ -280,6 +280,25 @@ The default value is `'keep'`. - `'keep'` The session in the store will be kept, but modifications made during the request are ignored and not saved. +##### nextopen +Close the browser to save the session, of course, you must configure the expiration time for the sessionID. + +The default value is `true`. + + - `false` cookie.maxAge is any, User closes the browser sessionID reset; + +For example,The following Settings. The user if not close the browser for more than 20 minutes, the session will also be reset. + +```js +var app = express() +app.set('trust proxy', 1) // trust first proxy +app.use(session({ + secret: 'keyboard cat', + cookie: { maxAge: 60000 * 20} + nextopen: false +})) +``` + ### req.session To store or access session data, simply use the request property `req.session`, diff --git a/index.js b/index.js index 8db4eca3..0431cd3d 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ var crc = require('crc').crc32; var debug = require('debug')('express-session'); var deprecate = require('depd')('express-session'); var parseUrl = require('parseurl'); +var querystring = require('querystring'); var uid = require('uid-safe').sync , onHeaders = require('on-headers') , signature = require('cookie-signature') @@ -79,6 +80,7 @@ var defer = typeof setImmediate === 'function' * @param {String|Array} [options.secret] Secret for signing session ID * @param {Object} [options.store=MemoryStore] Session store * @param {String} [options.unset] + * @param {String} [options.nextopen] Whether save session at the next open browser。 * @return {Function} middleware * @public */ @@ -113,6 +115,14 @@ function session(options) { // get the cookie signing secret var secret = opts.secret + // get onoff nextopen + var nextopen = options.nextopen === undefined ? true : options.nextopen + var sessionID_Dep; + + if(!nextopen && (cookieOptions.maxAge || cookieOptions.expires) && (new Cookie(cookieOptions)).expires > Date.now()){ + sessionID_Dep = name + '.dep'; + } + if (typeof generateId !== 'function') { throw new TypeError('genid option must be a function'); } @@ -176,6 +186,16 @@ function session(options) { }) return function session(req, res, next) { + // Processing reopen the browser session + if(sessionID_Dep){ + if(!req.cookies[sessionID_Dep]){ + delete req.cookies[name] + req.headers.cookie = querystring.stringify(req.cookies, ';', '=') + //res.cookie(sessionID_Dep,'Dep',{httpOnly:true}) + setcookie(res, sessionID_Dep, "Dep", "Dep", {httpOnly:true}); + } + } + // self-awareness if (req.session) { next() diff --git a/test/session.js b/test/session.js index 6711df98..2324f159 100644 --- a/test/session.js +++ b/test/session.js @@ -900,6 +900,108 @@ describe('session()', function(){ }); }); + describe('nextopen option', function(){ + it('should default to true',function(done){ + var app = express(),mark = 0; + app.use(cookieParser()); + app.use(session({ secret: 'keyboard cat', cookie: { maxAge: min }})); + app.use(function(req, res, next){ + var save = req.session.save; + if(!mark){ + mark = req.session.user = 'bob'; + } + res.setHeader("test-user",req.session.user || 'undefined') + res.end(); + }); + request(app) + .get('/') + .expect('test-user','bob') + .expect(200, function(err, res){ + if (err) return done(err); + request(app) + .get('/') + .set('Cookie', cookie(res)) + .expect('test-user','bob') + .expect(200,done) + }); + }) + it('Clear no expiration time "cookie" (analog browser is closed) session loss',function(done){ + var app = express(),mark=0; + app.use(cookieParser()); + app.use(session({nextopen: false, secret: 'keyboard cat', cookie: { maxAge: min }})); + app.use(function(req, res, next){ + var save = req.session.save; + if(!mark){ + mark = req.session.user = 'bob'; + } + res.setHeader("test-user",req.session.user || 'undefined') + res.end(); + }); + request(app) + .get('/') + .expect('test-user','bob') + .expect(function(res){ + var cookies = res.headers['set-cookie'] + for(var i in cookies){ + var v = cookies[i] + if(v.indexOf('connect.sid.dep') === 0) return; + } + return new Error('nextopen not working'); + }) + .expect(200, function(err, res){ + if (err) return done(err); + var cookies = res.headers['set-cookie'] + for(var i = 0; i < cookies.length; i++){ + var v = cookies[i]; + if(v.indexOf('Expires=') == -1){ + cookies.splice(i,1); + i--; + }else{ + cookies[i] = v.split(';')[0] + } + } + request(app) + .get('/') + .set('Cookie', cookies.join(';')) + .expect(function(res){ + if(res.headers['test-user'] == "bob") return Error ('Clear session failed'); + }) + .expect(200,done) + }); + }) + it('maxAge is null, not take effect then "false"',function(done){ + var app = express(),mark=0; + app.use(session({nextopen:false, secret: 'keyboard cat', cookie: { maxAge: null }})); + app.use(function(req, res, next){ + var save = req.session.save; + if(!mark){ + mark = req.session.user = 'bob'; + } + res.setHeader("test-user",req.session.user || 'undefined') + res.end(); + }); + request(app) + .get('/') + .expect('test-user','bob') + .expect(function(res){ + var cookies = res.headers['set-cookie'] + for(var i in cookies){ + var v = cookies[i] + assert.ok(v.indexOf('connect.sid.dep') !== 0,'nextopen Working Error') + } + }) + .expect(200, function(err, res){ + if (err) return done(err); + console.log(res.body) + request(app) + .get('/') + .set('Cookie', cookie(res)) + .expect('test-user','bob') + .expect(200,done) + }); + }) + }); + describe('resave option', function(){ it('should default to true', function(done){ var store = new session.MemoryStore() From ba15f5090b32af75d72b572e1ac8c0ed801c6075 Mon Sep 17 00:00:00 2001 From: cnwhy Date: Tue, 7 Mar 2017 19:29:38 +0800 Subject: [PATCH 3/3] name to @cnwhy/express-session and into npm --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 24de3879..02f4dd73 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "express-session", + "name": "@cnwhy/express-session", "version": "1.15.2", "description": "Simple session middleware for Express", "author": "TJ Holowaychuk (http://tjholowaychuk.com)", @@ -7,7 +7,7 @@ "Douglas Christopher Wilson ", "Joe Wagner " ], - "repository": "expressjs/session", + "repository": "cnwhy/session", "license": "MIT", "dependencies": { "cookie": "0.3.1",