Skip to content

Commit

Permalink
Merge e6474d0 into 001926f
Browse files Browse the repository at this point in the history
  • Loading branch information
dead-horse committed Jan 9, 2018
2 parents 001926f + e6474d0 commit 29a75c0
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 10 deletions.
14 changes: 12 additions & 2 deletions Readme.md
Expand Up @@ -26,7 +26,9 @@
[download-image]: https://img.shields.io/npm/dm/koa-session.svg?style=flat-square
[download-url]: https://npmjs.org/package/koa-session

Simple cookie-based session middleware for Koa.
Simple session middleware for Koa. Defaults to cookie-based sessions and supports external stores.

*Requires Node 7.6 or greater for async/await support*

## Installation

Expand Down Expand Up @@ -120,12 +122,20 @@ app.use(convert(session(app)));

Once you passed `options.store`, session is strong dependent on your external store, you can't access session if your external store is down. **Use external session stores only if necessary, avoid use session as a cache, keep session lean and stored by cookie!**

The way of generating external session id is controlled by the `options.genid`, which defaults to `uid.sync(24)`.
The way of generating external session id is controlled by the `options.genid`, which defaults to `Date.now() + '-' + uid.sync(24)`.

If you want to add prefix for all external session id, you can use `options.prefix`, it will not work if `options.genid` present.

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.
Expand Down
4 changes: 2 additions & 2 deletions index.js
Expand Up @@ -96,8 +96,8 @@ function formatOpts(opts) {
}

if (!opts.genid) {
if (opts.prefix) opts.genid = () => opts.prefix + uid.sync(24);
else opts.genid = () => uid.sync(24);
if (opts.prefix) opts.genid = () => `${opts.prefix}${Date.now()}-${uid.sync(24)}`;
else opts.genid = () => `${Date.now()}-${uid.sync(24)}`;
}

return opts;
Expand Down
19 changes: 13 additions & 6 deletions lib/context.js
Expand Up @@ -14,6 +14,7 @@ class ContextSession {

constructor(ctx, opts) {
this.ctx = ctx;
this.app = ctx.app;
this.opts = Object.assign({}, opts);
this.store = this.opts.ContextStore ? new this.opts.ContextStore(ctx) : this.opts.store;
}
Expand Down Expand Up @@ -79,7 +80,7 @@ class ContextSession {
}

const json = yield 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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -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": {
Expand Down
20 changes: 20 additions & 0 deletions test/store.test.js
Expand Up @@ -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;
Expand Down Expand Up @@ -442,6 +444,7 @@ describe('Koa Session External Store', () => {

describe('and expired', () => {
it('should expire the sess', done => {
done = pedding(done, 2);
const app = App({ maxAge: 100 });

app.use(function* () {
Expand All @@ -453,6 +456,11 @@ describe('Koa Session External Store', () => {

this.body = this.session.message || '';
});
app.on('session:expired', args => {
assert(args.key.match(/^\d+-/));
assert(args.value);
done();
});

const server = app.listen();

Expand Down Expand Up @@ -535,12 +543,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(function* () {
this.body = String(this.session.isNew);
});

app.on('session:missed', args => {
assert(args.key === 'invalid-key');
done();
});

request(app.listen())
.get('/')
.set('cookie', 'koa:sess=invalid-key')
Expand All @@ -551,6 +565,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 = koa();

app.keys = [ 'a', 'b' ];
Expand All @@ -573,6 +588,11 @@ describe('Koa Session External Store', () => {
uid: this.cookies.get('uid'),
};
});
app.on('session:invalid', args => {
assert(args.key);
assert(args.value);
done();
});

request(app.callback())
.get('/')
Expand Down

0 comments on commit 29a75c0

Please sign in to comment.