diff --git a/Readme.md b/Readme.md index bee6427..271fae9 100644 --- a/Readme.md +++ b/Readme.md @@ -26,7 +26,7 @@ [download-image]: https://img.shields.io/npm/dm/koa-session.svg?style=flat-square [download-url]: https://npmjs.org/package/koa-session - Simple session middleware for Koa. Defaults to cookie-based sessions and supports external stores. + Simple session middleware for Koa. Defaults to cookie-based sessions and supports external stores. *Requires Node 7.6 or greater for async/await support* @@ -117,6 +117,14 @@ console.log('listening on port 3000'); If your session store requires data or utilities from context, `opts.ContextStore` is alse supported. `ContextStore` must be a class which claims three instance methods demonstrated above. `new ContextStore(ctx)` will be executed on every request. +### Events + +`koa-session` will emit event on `app` when session expired or invalid: + +- `session:missed`: can't get session value from external store. +- `session:invalid`: session value is invalid. +- `session:expired`: session value is expired. + ### Session#isNew Returns __true__ if the session is new. diff --git a/lib/context.js b/lib/context.js index c4622a1..ea9cd74 100644 --- a/lib/context.js +++ b/lib/context.js @@ -14,6 +14,7 @@ class ContextSession { constructor(ctx, opts) { this.ctx = ctx; + this.app = ctx.app; this.opts = opts || {}; this.store = this.opts.ContextStore ? new this.opts.ContextStore(ctx) : this.opts.store; } @@ -79,7 +80,7 @@ class ContextSession { } const json = await this.store.get(externalKey, opts.maxAge, { rolling: opts.rolling }); - if (!this.valid(json)) { + if (!this.valid(json, externalKey)) { // create a new `externalKey` this.create(); return; @@ -144,23 +145,29 @@ class ContextSession { /** * verify session(expired or ) - * @param {Object} json session object + * @param {Object} value session object + * @param {Object} key session externalKey(optional) * @return {Boolean} valid * @api private */ - valid(json) { - if (!json) return false; + valid(value, key) { + if (!value) { + this.app.emit('session:missed', { key, value }); + return false; + } - if (json._expire && json._expire < Date.now()) { + if (value._expire && value._expire < Date.now()) { debug('expired session'); + this.app.emit('session:expired', { key, value }); return false; } const valid = this.opts.valid; - if (typeof valid === 'function' && !valid(this.ctx, json)) { + if (typeof valid === 'function' && !valid(this.ctx, value)) { // valid session value fail, ignore this session debug('invalid session'); + this.app.emit('session:invalid', { key, value }); return false; } return true; diff --git a/package.json b/package.json index d12da0b..f6c0513 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "crc": "^3.4.4", "debug": "^2.2.0", "is-type-of": "^1.0.0", + "pedding": "^1.1.0", "uid-safe": "^2.1.3" }, "engines": { diff --git a/test/store.test.js b/test/store.test.js index 82996ac..d8c0976 100644 --- a/test/store.test.js +++ b/test/store.test.js @@ -6,6 +6,8 @@ const should = require('should'); const mm = require('mm'); const session = require('..'); const store = require('./store'); +const pedding = require('pedding'); +const assert = require('assert'); describe('Koa Session External Store', () => { let cookie; @@ -442,8 +444,13 @@ describe('Koa Session External Store', () => { describe('and expired', () => { it('should expire the sess', done => { + done = pedding(done, 2); const app = App({ maxAge: 100 }); - + app.on('session:expired', args => { + assert(args.key); + assert(args.value); + done(); + }); app.use(async function(ctx) { if (ctx.method === 'POST') { ctx.session.message = 'hi'; @@ -535,12 +542,18 @@ describe('Koa Session External Store', () => { describe('when store return empty', () => { it('should create new Session', done => { + done = pedding(done, 2); const app = App({ signed: false }); app.use(async function(ctx) { ctx.body = String(ctx.session.isNew); }); + app.on('session:missed', args => { + assert(args.key === 'invalid-key'); + done(); + }); + request(app.listen()) .get('/') .set('cookie', 'koa:sess=invalid-key') @@ -551,6 +564,7 @@ describe('Koa Session External Store', () => { describe('when valid and beforeSave set', () => { it('should ignore session when uid changed', done => { + done = pedding(done, 2); const app = new Koa(); app.keys = [ 'a', 'b' ]; @@ -573,6 +587,11 @@ describe('Koa Session External Store', () => { uid: ctx.cookies.get('uid'), }; }); + app.on('session:invalid', args => { + assert(args.key); + assert(args.value); + done(); + }); request(app.callback()) .get('/')