add app.keys support
This commit is contained in:
parent
52307eeb72
commit
0362c8e457
4 changed files with 137 additions and 3 deletions
|
@ -59,6 +59,26 @@ http.createServer(app.callback()).listen(3001);
|
||||||
Add the given middleware function to this application. See [Middleware](#middleware) for
|
Add the given middleware function to this application. See [Middleware](#middleware) for
|
||||||
more information.
|
more information.
|
||||||
|
|
||||||
|
### app.keys=
|
||||||
|
|
||||||
|
Set signed cookie keys.
|
||||||
|
|
||||||
|
These are passed to [KeyGrip](https://github.com/jed/keygrip),
|
||||||
|
however you may also pass your own `KeyGrip` instance. For
|
||||||
|
example the following are acceptable:
|
||||||
|
|
||||||
|
```js
|
||||||
|
app.keys = ['im a newer secret', 'i like turtle'];
|
||||||
|
app.keys = new KeyGrip(['im a newer secret', 'i like turtle'], 'sha256');
|
||||||
|
```
|
||||||
|
|
||||||
|
These keys may be rotated and are used when signing cookies
|
||||||
|
with the `{ signed: true }` option:
|
||||||
|
|
||||||
|
```js
|
||||||
|
this.cookies.set('name', 'tobi', { signed: true });
|
||||||
|
```
|
||||||
|
|
||||||
## Handling Requests
|
## Handling Requests
|
||||||
|
|
||||||
Koa requests are manipulated using a `Context` object containing both a Koa `Request` and `Response` object. For more information on these view:
|
Koa requests are manipulated using a `Context` object containing both a Koa `Request` and `Response` object. For more information on these view:
|
||||||
|
|
|
@ -10,6 +10,7 @@ var context = require('./context');
|
||||||
var request = require('./request');
|
var request = require('./request');
|
||||||
var response = require('./response');
|
var response = require('./response');
|
||||||
var Cookies = require('cookies');
|
var Cookies = require('cookies');
|
||||||
|
var Keygrip = require('keygrip');
|
||||||
var Stream = require('stream');
|
var Stream = require('stream');
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
var co = require('co');
|
var co = require('co');
|
||||||
|
@ -96,11 +97,42 @@ app.callback = function(){
|
||||||
|
|
||||||
return function(req, res, next){
|
return function(req, res, next){
|
||||||
var ctx = self.createContext(req, res);
|
var ctx = self.createContext(req, res);
|
||||||
|
|
||||||
co.call(ctx, gen)(next || ctx.onerror);
|
co.call(ctx, gen)(next || ctx.onerror);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set signed cookie keys.
|
||||||
|
*
|
||||||
|
* These are passed to [KeyGrip](https://github.com/jed/keygrip),
|
||||||
|
* however you may also pass your own `KeyGrip` instance. For
|
||||||
|
* example the following are acceptable:
|
||||||
|
*
|
||||||
|
* app.keys = ['im a newer secret', 'i like turtle'];
|
||||||
|
* app.keys = new KeyGrip(['im a newer secret', 'i like turtle'], 'sha256');
|
||||||
|
*
|
||||||
|
* @param {Array|KeyGrip} keys
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
app.__defineSetter__('keys', function(keys){
|
||||||
|
var ok = Array.isArray(keys) || keys instanceof Keygrip;
|
||||||
|
if (!ok) throw new TypeError('app.keys must be an array or Keygrip');
|
||||||
|
if (!(keys instanceof Keygrip)) keys = new Keygrip(keys);
|
||||||
|
this._keys = keys;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get `Keygrip` instance.
|
||||||
|
*
|
||||||
|
* @return {Keygrip}
|
||||||
|
* @api public
|
||||||
|
*/
|
||||||
|
|
||||||
|
app.__defineGetter__('keys', function(){
|
||||||
|
return this._keys;
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a new context.
|
* Initialize a new context.
|
||||||
*
|
*
|
||||||
|
@ -116,8 +148,8 @@ app.createContext = function(req, res){
|
||||||
context.res = request.res = response.res = res;
|
context.res = request.res = response.res = res;
|
||||||
request.ctx = response.ctx = context;
|
request.ctx = response.ctx = context;
|
||||||
context.onerror = context.onerror.bind(context);
|
context.onerror = context.onerror.bind(context);
|
||||||
context.cookies = new Cookies(req, res);
|
|
||||||
context.originalUrl = request.originalUrl = req.url;
|
context.originalUrl = request.originalUrl = req.url;
|
||||||
|
context.cookies = new Cookies(req, res, this.keys);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
"fresh": "~0.2.0",
|
"fresh": "~0.2.0",
|
||||||
"negotiator": "~0.3.0",
|
"negotiator": "~0.3.0",
|
||||||
"koa-compose": "~2.0.0",
|
"koa-compose": "~2.0.0",
|
||||||
"cookies": "~0.3.6"
|
"cookies": "~0.3.6",
|
||||||
|
"keygrip": "~0.2.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bytes": "~0.2.1",
|
"bytes": "~0.2.1",
|
||||||
|
|
81
test/context/cookies.js
Normal file
81
test/context/cookies.js
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
var koa = require('../..')
|
||||||
|
var request = require('supertest');
|
||||||
|
|
||||||
|
describe('ctx.cookies.set()', function(){
|
||||||
|
it('should set an unsigned cookie', function(done){
|
||||||
|
var app = koa();
|
||||||
|
|
||||||
|
app.use(function *(next){
|
||||||
|
this.cookies.set('name', 'jon');
|
||||||
|
this.status = 204;
|
||||||
|
})
|
||||||
|
|
||||||
|
var server = app.listen();
|
||||||
|
|
||||||
|
request(server)
|
||||||
|
.get('/')
|
||||||
|
.expect(204)
|
||||||
|
.end(function(err, res){
|
||||||
|
if (err) return done(err);
|
||||||
|
|
||||||
|
res.headers['set-cookie'].some(function(cookie){
|
||||||
|
return /^name=/.test(cookie);
|
||||||
|
}).should.be.ok;
|
||||||
|
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with .signed', function(){
|
||||||
|
describe('when no .keys are set', function(){
|
||||||
|
it('should error', function(done){
|
||||||
|
var app = koa();
|
||||||
|
|
||||||
|
app.use(function *(next){
|
||||||
|
try {
|
||||||
|
this.cookies.set('foo', 'bar', { signed: true });
|
||||||
|
} catch (err) {
|
||||||
|
this.body = err.message;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
request(app.listen())
|
||||||
|
.get('/')
|
||||||
|
.expect('Cannot call method \'sign\' of undefined', done);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should send a signed cookie', function(done){
|
||||||
|
var app = koa();
|
||||||
|
|
||||||
|
app.keys = ['a', 'b'];
|
||||||
|
|
||||||
|
app.use(function *(next){
|
||||||
|
this.cookies.set('name', 'jon', { signed: true });
|
||||||
|
this.status = 204;
|
||||||
|
})
|
||||||
|
|
||||||
|
var server = app.listen();
|
||||||
|
|
||||||
|
request(server)
|
||||||
|
.get('/')
|
||||||
|
.expect(204)
|
||||||
|
.end(function(err, res){
|
||||||
|
if (err) return done(err);
|
||||||
|
|
||||||
|
var cookies = res.headers['set-cookie'];
|
||||||
|
|
||||||
|
cookies.some(function(cookie){
|
||||||
|
return /^name=/.test(cookie);
|
||||||
|
}).should.be.ok;
|
||||||
|
|
||||||
|
cookies.some(function(cookie){
|
||||||
|
return /^name\.sig=/.test(cookie);
|
||||||
|
}).should.be.ok;
|
||||||
|
|
||||||
|
done();
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in a new issue