Skip to content

Commit

Permalink
feat: Add Session.regenerate() method (#221)
Browse files Browse the repository at this point in the history
And make both save() and regenerate() compatible with koa-passport

closes #74
  • Loading branch information
lehni authored Feb 4, 2023
1 parent 6b70431 commit 4cd3bef
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 9 deletions.
12 changes: 7 additions & 5 deletions lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class ContextSession {
* @api public
*/

async commit() {
async commit({ save = false, regenerate = false } = {}) {
const session = this.session;
const opts = this.opts;
const ctx = this.ctx;
Expand All @@ -226,8 +226,13 @@ class ContextSession {
await this.remove();
return;
}
if (regenerate) {
await this.remove();
if (this.store) this.externalKey = opts.genid && opts.genid(ctx);
}

const reason = this._shouldSaveSession();
// force save session when `session._requireSave` set
const reason = save || regenerate || session._requireSave ? 'force' : this._shouldSaveSession();
debug('should save session: %s', reason);
if (!reason) return;

Expand All @@ -243,9 +248,6 @@ class ContextSession {
const prevHash = this.prevHash;
const session = this.session;

// force save session when `session._requireSave` set
if (session._requireSave) return 'force';

// do nothing if new and not populated
const json = session.toJSON();
if (!prevHash && !Object.keys(json).length) return '';
Expand Down
32 changes: 28 additions & 4 deletions lib/session.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,23 @@ class Session {
/**
* save this session no matter whether it is populated
*
* @param {Function} callback the optional function to call after saving the session
* @api public
*/

save() {
this._requireSave = true;
save(callback) {
return this.commit({ save: true }, callback);
}

/**
* regenerate this session
*
* @param {Function} callback the optional function to call after regenerating the session
* @api public
*/

regenerate(callback) {
return this.commit({ regenerate: true }, callback);
}

/**
Expand All @@ -130,10 +142,22 @@ class Session {
* @api public
*/

async manuallyCommit() {
await this._sessCtx.commit();
manuallyCommit() {
return this.commit();
}

commit(options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
const promise = this._sessCtx.commit(options);
if (callback) {
promise.then(() => callback(), callback);
} else {
return promise;
}
}
}

module.exports = Session;
42 changes: 42 additions & 0 deletions test/cookie.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,48 @@ describe('Koa Session Cookie', () => {
});
});

describe('ctx.session.regenerate', () => {
it('should change the session key, but not content', done => {
const app = new App();
const message = 'hi';
app.use(async function(ctx, next) {
ctx.session = { message: 'hi' };
await next();
});

app.use(async function(ctx, next) {
const sessionKey = ctx.cookies.get('koa.sess');
if (sessionKey) {
await ctx.session.regenerate();
}
await next();
});

app.use(async function(ctx) {
ctx.session.message.should.equal(message);
ctx.body = '';
});
let koaSession = null;
request(app.callback())
.get('/')
.expect(200, (err, res) => {
should.not.exist(err);
koaSession = res.headers['set-cookie'][0];
koaSession.should.containEql('koa.sess=');
request(app.callback())
.get('/')
.set('Cookie', koaSession)
.expect(200, (err, res) => {
should.not.exist(err);
const cookies = res.headers['set-cookie'][0];
cookies.should.containEql('koa.sess=');
cookies.should.not.equal(koaSession);
done();
});
});
});
});

describe('when get session before enter session middleware', () => {
it('should work', done => {
const app = new Koa();
Expand Down
42 changes: 42 additions & 0 deletions test/store.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,48 @@ describe('Koa Session External Store', () => {
});
});

describe('ctx.session.regenerate', () => {
it('should change the session key, but not content', done => {
const app = new App();
const message = 'hi';
app.use(async function(ctx, next) {
ctx.session = { message: 'hi' };
await next();
});

app.use(async function(ctx, next) {
const sessionKey = ctx.cookies.get('koa.sess');
if (sessionKey) {
await ctx.session.regenerate();
}
await next();
});

app.use(async function(ctx) {
ctx.session.message.should.equal(message);
ctx.body = '';
});
let koaSession = null;
request(app.callback())
.get('/')
.expect(200, (err, res) => {
should.not.exist(err);
koaSession = res.headers['set-cookie'][0];
koaSession.should.containEql('koa.sess=');
request(app.callback())
.get('/')
.set('Cookie', koaSession)
.expect(200, (err, res) => {
should.not.exist(err);
const cookies = res.headers['set-cookie'][0];
cookies.should.containEql('koa.sess=');
cookies.should.not.equal(koaSession);
done();
});
});
});
});

describe('when store return empty', () => {
it('should create new Session', done => {
done = pedding(done, 2);
Expand Down

0 comments on commit 4cd3bef

Please sign in to comment.