From 5735cbd8f5e324f1e15574e09769cf3e7536e02b Mon Sep 17 00:00:00 2001 From: Georgi Petkov Date: Mon, 14 Sep 2020 22:44:43 +0200 Subject: [PATCH 1/7] add context to external store .get() and .set() params --- .prettierignore | 1 + lib/context.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..f59ec20 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/lib/context.js b/lib/context.js index 1bb41a8..e3a3970 100644 --- a/lib/context.js +++ b/lib/context.js @@ -87,7 +87,7 @@ class ContextSession { return; } - const json = await this.store.get(externalKey, opts.maxAge, { rolling: opts.rolling }); + const json = await this.store.get(externalKey, opts.maxAge, { ctx, rolling: opts.rolling }); if (!this.valid(json, externalKey)) { // create a new `externalKey` this.create(); @@ -320,6 +320,7 @@ class ContextSession { } await this.store.set(externalKey, json, maxAge, { changed, + ctx: this.ctx, rolling: opts.rolling, }); if (opts.externalKey) { From 73d80152df0b848488028884265eaa13c0fd6945 Mon Sep 17 00:00:00 2001 From: Georgi Petkov Date: Tue, 15 Sep 2020 11:48:46 +0200 Subject: [PATCH 2/7] restricting store.get/set options param to ctx.state only. ctx.state added as options param to store.destroy method too --- lib/context.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/context.js b/lib/context.js index e3a3970..ac7f60e 100644 --- a/lib/context.js +++ b/lib/context.js @@ -87,7 +87,7 @@ class ContextSession { return; } - const json = await this.store.get(externalKey, opts.maxAge, { ctx, rolling: opts.rolling }); + const json = await this.store.get(externalKey, opts.maxAge, { state: ctx.state, rolling: opts.rolling }); if (!this.valid(json, externalKey)) { // create a new `externalKey` this.create(); @@ -284,7 +284,7 @@ class ContextSession { const key = opts.key; const externalKey = this.externalKey; - if (externalKey) await this.store.destroy(externalKey); + if (externalKey) await this.store.destroy(externalKey, {state: this.ctx.state}); ctx.cookies.set(key, '', opts); } @@ -320,7 +320,7 @@ class ContextSession { } await this.store.set(externalKey, json, maxAge, { changed, - ctx: this.ctx, + state: this.ctx.state, rolling: opts.rolling, }); if (opts.externalKey) { From c821029d48c8f221e13a8fb2b83ee0e4c0df6e46 Mon Sep 17 00:00:00 2001 From: Georgi Petkov Date: Fri, 18 Sep 2020 11:37:12 +0200 Subject: [PATCH 3/7] using ctx instad of ctx.state --- lib/context.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/context.js b/lib/context.js index ac7f60e..605a7db 100644 --- a/lib/context.js +++ b/lib/context.js @@ -87,7 +87,7 @@ class ContextSession { return; } - const json = await this.store.get(externalKey, opts.maxAge, { state: ctx.state, rolling: opts.rolling }); + const json = await this.store.get(externalKey, opts.maxAge, { ctx, rolling: opts.rolling }); if (!this.valid(json, externalKey)) { // create a new `externalKey` this.create(); @@ -284,7 +284,7 @@ class ContextSession { const key = opts.key; const externalKey = this.externalKey; - if (externalKey) await this.store.destroy(externalKey, {state: this.ctx.state}); + if (externalKey) await this.store.destroy(externalKey, {ctx}); ctx.cookies.set(key, '', opts); } @@ -320,7 +320,7 @@ class ContextSession { } await this.store.set(externalKey, json, maxAge, { changed, - state: this.ctx.state, + state: this.ctx, rolling: opts.rolling, }); if (opts.externalKey) { From 5158c730cfa1fa5c82e9110e40303b23825f16b9 Mon Sep 17 00:00:00 2001 From: Georgi Petkov Date: Sun, 20 Sep 2020 13:06:29 +0200 Subject: [PATCH 4/7] .set(..., options) provides now options.ctx instead of options.state --- lib/context.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/context.js b/lib/context.js index 605a7db..249a56c 100644 --- a/lib/context.js +++ b/lib/context.js @@ -320,7 +320,7 @@ class ContextSession { } await this.store.set(externalKey, json, maxAge, { changed, - state: this.ctx, + ctx: this.ctx, rolling: opts.rolling, }); if (opts.externalKey) { From d752ca1eafd06a4f4e43f33b919082c7e5ea30f7 Mon Sep 17 00:00:00 2001 From: Georgi Petkov Date: Sun, 27 Sep 2020 13:25:20 +0200 Subject: [PATCH 5/7] test if store has access to ctx --- test/store_with_ctx.js | 23 ++++++++++ test/store_with_ctx.test.js | 85 +++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 test/store_with_ctx.js create mode 100644 test/store_with_ctx.test.js diff --git a/test/store_with_ctx.js b/test/store_with_ctx.js new file mode 100644 index 0000000..a64939c --- /dev/null +++ b/test/store_with_ctx.js @@ -0,0 +1,23 @@ +'use strict'; + +const sessions = {}; + +module.exports = { + async get(key, maxAge, options) { + // check access to options.ctx + options.ctx.state.test = 'get'; + return sessions[key]; + }, + + async set(key, sess, maxAge, options) { + // check access to options.ctx + options.ctx.state.test = 'set'; + sessions[key] = sess; + }, + + async destroy(key, options) { + // check access to options.ctx + options.ctx.state.test = 'destroyed'; + sessions[key] = undefined; + }, +}; \ No newline at end of file diff --git a/test/store_with_ctx.test.js b/test/store_with_ctx.test.js new file mode 100644 index 0000000..8fbe95b --- /dev/null +++ b/test/store_with_ctx.test.js @@ -0,0 +1,85 @@ +'use strict'; + +const Koa = require('koa'); +const request = require('supertest'); +const should = require('should'); +const session = require('..'); +const store = require('./store_with_ctx'); +const pedding = require('pedding'); +const assert = require('assert'); +const sleep = require('mz-modules/sleep'); + +describe('Koa Session External Store methods can acceess Koa context', () => { + let cookie; + + describe('new session', () => { + describe('when not accessed', () => { + it('should not set ctx.state.test variable', async () => { + const app = App(); + + request(app.callback()) + .get('/') + .expect('undefined'); + }); + }); + + describe('when populated', () => { + it('should set ctx.state.test variable', done => { + const app = App(); + + app.use(async ctx => { + if (ctx.path === '/set') ctx.session = { foo: 'bar' }; + }); + + request(app.listen()) + .get('/set') + .expect(200, (err, res) => { + if (err) return done(err); + cookie = res.header['set-cookie'].join(';'); + res.text.should.equal('set'); + done(); + }); + }); + }); + + describe('when accessed', () => { + it('should access ctx.state.test variable', async () => { + const app = App(); + + request(app.callback()) + .get('/') + .set('Cookie', cookie) + .expect('get'); + }); + }); + + describe('session destroyed', () => { + it('should access ctx.state.test variable', async () => { + const app = App(); + + app.use(async ctx => { + if (ctx.path === '/destroy') ctx.session = null; + }); + + request(app.callback()) + .get('/destroy') + .set('Cookie', cookie) + .expect('destroyed'); + }); + }); + }); +}); + +function App(options) { + const app = new Koa(); + app.keys = [ 'a', 'b' ]; + options = options || {}; + options.store = store; + app.use(async (ctx, next) => { + await next(); + ctx.body = ctx.state.test === undefined ? 'undefined' : ctx.state.test; + }); + + app.use(session(options, app)); + return app; +} From e961ea11c946fa90b398df0faad1133ad5aa8612 Mon Sep 17 00:00:00 2001 From: Georgi Petkov Date: Sun, 27 Sep 2020 14:01:33 +0200 Subject: [PATCH 6/7] docs: External store methods have ctx in options param --- .prettierignore | 1 - Readme.md | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 .prettierignore diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index f59ec20..0000000 --- a/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -* \ No newline at end of file diff --git a/Readme.md b/Readme.md index 35bae2d..ee59469 100644 --- a/Readme.md +++ b/Readme.md @@ -111,9 +111,9 @@ console.log('listening on port 3000'); You can store the session content in external stores (Redis, MongoDB or other DBs) by passing `options.store` with three methods (these need to be async functions): - - `get(key, maxAge, { rolling })`: get session object by key - - `set(key, sess, maxAge, { rolling, changed })`: set session object for key, with a `maxAge` (in ms) - - `destroy(key)`: destroy session for key + - `get(key, maxAge, { rolling, ctx })`: get session object by key + - `set(key, sess, maxAge, { rolling, changed, ctx })`: set session object for key, with a `maxAge` (in ms) + - `destroy(key, {ctx})`: destroy session for key Once you pass `options.store`, session storage is dependent on your external store -- you can't access the session if your external store is down. **Use external session stores only if necessary, avoid using session as a cache, keep the session lean, and store it in a cookie if possible!** From 3d2c89ab48a53dcf10d2452536568416def5cacb Mon Sep 17 00:00:00 2001 From: Georgi Petkov Date: Fri, 2 Oct 2020 11:54:45 +0200 Subject: [PATCH 7/7] trying to satisfy travis CI --- lib/context.js | 2 +- test/store_with_ctx.js | 2 +- test/store_with_ctx.test.js | 4 ---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/context.js b/lib/context.js index 249a56c..ccb8d5c 100644 --- a/lib/context.js +++ b/lib/context.js @@ -284,7 +284,7 @@ class ContextSession { const key = opts.key; const externalKey = this.externalKey; - if (externalKey) await this.store.destroy(externalKey, {ctx}); + if (externalKey) await this.store.destroy(externalKey, { ctx }); ctx.cookies.set(key, '', opts); } diff --git a/test/store_with_ctx.js b/test/store_with_ctx.js index a64939c..2ebd234 100644 --- a/test/store_with_ctx.js +++ b/test/store_with_ctx.js @@ -20,4 +20,4 @@ module.exports = { options.ctx.state.test = 'destroyed'; sessions[key] = undefined; }, -}; \ No newline at end of file +}; diff --git a/test/store_with_ctx.test.js b/test/store_with_ctx.test.js index 8fbe95b..21fe43a 100644 --- a/test/store_with_ctx.test.js +++ b/test/store_with_ctx.test.js @@ -2,12 +2,8 @@ const Koa = require('koa'); const request = require('supertest'); -const should = require('should'); const session = require('..'); const store = require('./store_with_ctx'); -const pedding = require('pedding'); -const assert = require('assert'); -const sleep = require('mz-modules/sleep'); describe('Koa Session External Store methods can acceess Koa context', () => { let cookie;