diff --git a/.travis.yml b/.travis.yml index 1a6db11..f6566d5 100755 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: - - 0.10 - 4 + - 4.0 + - 5 diff --git a/README.md b/README.md index f23489d..94fa8e4 100755 --- a/README.md +++ b/README.md @@ -10,13 +10,7 @@ Lead Maintainer: [Marcus Stong](https://github.com/stongo) Crumb has been refactored to securely work with CORS, as [OWASP](https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet#Cross_Origin_Resource_Sharing) recommends using CSRF protection with CORS. -The `allowOrigins` option allows you to have fine grained control on which Cross Origin sites get the Crumb cookie set. This is useful for APIs that have some consumers only using GET routes (no Crumb token should be set) while other consumers have permission for POST/PUT/PATCH/DELETE routes. - -If the `allowOrigins` setting is not set, the server's `cors.origin` list will be used to determine when to set the Crumb cookie on Cross Origin requests. - -To use Crumb securely on a server that allows Same Origin requests and CORS, it's a requirement to set server `host` to a hostname rather than an IP for Crumb to determine same origin requests. If you use an IP as the server host, your Same Origin requests will not get the Crumb cookie set. - -**Note that Crumb will not work with `allowOrigins` or `cors.origin` set to "\*"** +**It is highly discouraged to have a production servers `cors.origin` setting set to "[\*]" or "true" with Crumb as it will leak the crumb token to potentially malicious sites** ## Plugin Options @@ -29,7 +23,6 @@ The following options are available when registering the plugin * 'cookieOptions' - storage options for the cookie containing the crumb, see the [server.state](http://hapijs.com/api#serverstatename-options) documentation of hapi for more information * 'restful' - RESTful mode that validates crumb tokens from "X-CSRF-Token" request header for POST, PUT, PATCH and DELETE server routes. Disables payload/query crumb validation (defaults to false) * 'skip' - a function with the signature of `function (request, reply) {}`, which when provided, is called for every request. If the provided function returns true, validation and generation of crumb is skipped (defaults to false) -* 'allowOrigins' - an array of origins to set crumb cookie on if CORS is enabled. Supports '\*' wildcards for domain segments and port ie '\*.domain.com' or 'domain.com:\*'. '\*' by itself is not allowed. Defaults to the server's `cors.origin` setting by default Additionally, some configuration can be passed on a per-route basis diff --git a/example/restful.js b/example/restful.js index 66fbef2..d93e737 100755 --- a/example/restful.js +++ b/example/restful.js @@ -1,11 +1,13 @@ -var Hapi = require('hapi'); +'use strict'; -var server = new Hapi.Server(); +const Hapi = require('hapi'); + +const server = new Hapi.Server(); server.connection({ host: '127.0.0.1', port: 8000 }); // Add Crumb plugin -server.register({ register: require('../'), options: { restful: true } }, function (err) { +server.register({ register: require('../'), options: { restful: true } }, (err) => { if (err) { throw err; @@ -38,7 +40,7 @@ server.route([ } ]); -server.start(function () { +server.start(() => { console.log('Example restful server running at:', server.info.uri); }); diff --git a/example/server.js b/example/server.js index 94dcd54..c0cde7f 100755 --- a/example/server.js +++ b/example/server.js @@ -1,6 +1,8 @@ -var Hapi = require('hapi'); +'use strict'; -var server = new Hapi.Server(); +const Hapi = require('hapi'); + +const server = new Hapi.Server(); server.connection({ host: '127.0.0.1', port: 8000 }); server.views({ @@ -10,7 +12,7 @@ server.views({ } }); -server.register({ register: require('../'), options: { cookieOptions: { isSecure: false } } }, function (err) { +server.register({ register: require('../'), options: { cookieOptions: { isSecure: false } } }, (err) => { if (err) { throw err; @@ -35,7 +37,7 @@ server.route({ } }); -server.start(function () { +server.start(() => { console.log('Example server running at:', server.info.uri); }); diff --git a/lib/index.js b/lib/index.js index f944997..9408eb2 100755 --- a/lib/index.js +++ b/lib/index.js @@ -1,15 +1,17 @@ +'use strict'; + // Load modules -var Stream = require('stream'); -var Boom = require('boom'); -var Cryptiles = require('cryptiles'); -var Hoek = require('hoek'); -var Joi = require('joi'); +const Stream = require('stream'); +const Boom = require('boom'); +const Cryptiles = require('cryptiles'); +const Hoek = require('hoek'); +const Joi = require('joi'); // Declare internals -var internals = {}; +const internals = {}; internals.schema = Joi.object().keys({ @@ -19,8 +21,7 @@ internals.schema = Joi.object().keys({ addToViewContext: Joi.boolean().optional(), cookieOptions: Joi.object().keys(null), restful: Joi.boolean().optional(), - skip: Joi.func().optional(), - allowOrigins: Joi.array().items(Joi.string().valid('*').forbidden()).optional() + skip: Joi.func().optional() }); @@ -33,21 +34,20 @@ internals.defaults = { path: '/' }, restful: false, // Set to true for X-CSRF-Token header crumb validation. Disables payload/query validation - skip: false, // Set to a function which returns true when to skip crumb generation and validation - allowOrigins: null // A list of CORS origins to set crumb cookie on. Defaults to request.route.settings.settings.cors.origin + skip: false // Set to a function which returns true when to skip crumb generation and validation }; exports.register = function (server, options, next) { - var validateOptions = internals.schema.validate(options); + const validateOptions = internals.schema.validate(options); if (validateOptions.error) { return next(validateOptions.error); } - var settings = Hoek.applyToDefaults(internals.defaults, options); + const settings = Hoek.applyToDefaults(internals.defaults, options); - var routeDefaults = { + const routeDefaults = { key: settings.key, restful: settings.restful, source: 'payload' @@ -55,7 +55,7 @@ exports.register = function (server, options, next) { server.state(settings.key, settings.cookieOptions); - server.ext('onPostAuth', function (request, reply) { + server.ext('onPostAuth', (request, reply) => { // If skip function enabled. Call it and if returns true, do not attempt to do anything with crumb. @@ -80,7 +80,7 @@ exports.register = function (server, options, next) { if ((settings.autoGenerate || request.route.settings.plugins._crumb) && - (request.route.settings.cors ? internals.originParser(request.headers.origin, settings.allowOrigins || request.route.settings.cors.origin, request) : true)) { + (request.route.settings.cors ? request.info.cors.isOriginMatch : true)) { generate(request, reply); } @@ -96,7 +96,7 @@ exports.register = function (server, options, next) { return reply.continue(); } - var content = request[request.route.settings.plugins._crumb.source]; + const content = request[request.route.settings.plugins._crumb.source]; if (!content || content instanceof Stream) { return reply(Boom.forbidden()); @@ -117,7 +117,7 @@ exports.register = function (server, options, next) { return reply.continue(); } - var header = request.headers['x-csrf-token']; + const header = request.headers['x-csrf-token']; if (!header) { return reply(Boom.forbidden()); @@ -132,11 +132,11 @@ exports.register = function (server, options, next) { return reply.continue(); }); - server.ext('onPreResponse', function (request, reply) { + server.ext('onPreResponse', (request, reply) => { // Add to view context - var response = request.response; + const response = request.response; if (settings.addToViewContext && request.plugins.crumb && @@ -151,9 +151,9 @@ exports.register = function (server, options, next) { return reply.continue(); }); - var generate = function (request, reply) { + const generate = function (request, reply) { - var crumb = request.state[settings.key]; + let crumb = request.state[settings.key]; if (!crumb) { crumb = Cryptiles.randomString(settings.size); reply.state(settings.key, crumb, settings.cookieOptions); @@ -171,78 +171,3 @@ exports.register = function (server, options, next) { exports.register.attributes = { pkg: require('../package.json') }; - - -// Strip http or https from request host - -internals.trimHost = function (host) { - - this._host = host; - - if (host.indexOf('https://') === 0) { - this._host = this._host.substring(8); - } - if (host.indexOf('http://') === 0) { - this._host = this._host.substring(7); - } - - return this._host; -}; - - -// Parses allowOrigin setting - -internals.originParser = function (origin, allowOrigins, request) { - - var host = internals.trimHost(request.connection.info.uri); - var requestHost = request.headers.host; - this._match = false; - - // If a same origin request, pass check - - if (host === requestHost) { - this._match = true; - return this._match; - } - - // If no origin header is set and cross-origin, automatically fail check - - else if (!origin || allowOrigins.length === 0) { - return this._match; - } - - // Split origin in to port and domain - - this._origin = origin.split(':'); - this._originPort = this._origin.length === 3 ? this._origin[2] : null; - this._originParts = this._origin[1].split('.'); - - // Iterate through allowed origins list and check origin header matches - - for (var i = 0, il = allowOrigins.length; i < il; ++i) { - if (allowOrigins[i] === '*') { - return false; - } - - this._originAllow = allowOrigins[i].split(':'); - this._originAllowPort = this._originAllow.length === 3 ? this._originAllow[2] : null; - this._originAllowParts = this._originAllow[1].split('.'); - - if ((this._originPort && !this._originAllowPort) || (!this._originPort && this._originAllowPort) || (this._originAllowPort !== '*' && this._originPort !== this._originAllowPort)) { - this._match = false; - } - else { - for (var j = 0, jl = this._originAllowParts.length; j < jl; ++j) { - this._match = this._originAllowParts[j] === '//*' || this._originAllowParts[j] === this._originParts[j]; - if (!this._match) { - break; - } - } - if (this._match) { - return this._match; - } - } - } - - return this._match; -}; diff --git a/package.json b/package.json index b3b95c4..019d4a1 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "crumb", "description": "CSRF crumb generation and validation plugin", - "version": "5.0.0", + "version": "6.0.0", "repository": "git://github.com/hapijs/crumb", "bugs": { "url": "https://github.com/hapijs/crumb/issues" @@ -15,23 +15,23 @@ "session" ], "engines": { - "node": ">=0.10.32" + "node": ">=4.0.0" }, "dependencies": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "joi": "6.x.x" + "boom": "3.x.x", + "cryptiles": "3.x.x", + "hoek": "3.x.x", + "joi": "7.x.x" }, "peerDependencies": { - "hapi": ">=8.x.x" + "hapi": ">=12.x.x" }, "devDependencies": { - "code": "1.x.x", - "handlebars": "1.3.x", - "hapi": "9.x.x", - "lab": "6.x.x", - "vision": "^3.0.0" + "code": "2.x.x", + "handlebars": "^4.0.5", + "hapi": "12.x.x", + "lab": "8.x.x", + "vision": "^4.0.0" }, "scripts": { "test": "lab -r console -t 100 -a code -L", diff --git a/test/index.js b/test/index.js index da02ac0..244c1d7 100755 --- a/test/index.js +++ b/test/index.js @@ -1,35 +1,37 @@ +'use strict'; + // Load modules /*eslint "hapi/no-shadow-relaxed": 0*/ -var Stream = require('stream'); -var Code = require('code'); -var Crumb = require('../'); -var Hapi = require('hapi'); -var Lab = require('lab'); -var Hoek = require('hoek'); +const Stream = require('stream'); +const Code = require('code'); +const Crumb = require('../'); +const Hapi = require('hapi'); +const Lab = require('lab'); +const Hoek = require('hoek'); // Declare internals -var internals = {}; +const internals = {}; // Test shortcuts -var lab = exports.lab = Lab.script(); -var describe = lab.describe; -var it = lab.it; -var expect = Code.expect; -var vision = require('vision'); +const lab = exports.lab = Lab.script(); +const describe = lab.describe; +const it = lab.it; +const expect = Code.expect; +const Vision = require('vision'); -describe('Crumb', function () { +describe('Crumb', () => { - it('returns view with crumb', function (done) { + it('returns view with crumb', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection(); - var viewOptions = { + const viewOptions = { path: __dirname + '/templates', engines: { html: require('handlebars') @@ -38,7 +40,7 @@ describe('Crumb', function () { server.route([ { - method: 'GET', path: '/1', handler: function (request, reply) { + method: 'GET', path: '/1', handler: (request, reply) => { expect(request.plugins.crumb).to.exist(); expect(request.server.plugins.crumb.generate).to.exist(); @@ -50,20 +52,20 @@ describe('Crumb', function () { } }, { - method: 'POST', path: '/2', handler: function (request, reply) { + method: 'POST', path: '/2', handler: (request, reply) => { expect(request.payload).to.deep.equal({ key: 'value' }); return reply('valid'); } }, { - method: 'POST', path: '/3', config: { payload: { output: 'stream' } }, handler: function (request, reply) { + method: 'POST', path: '/3', config: { payload: { output: 'stream' } }, handler: (request, reply) => { return reply('never'); } }, { - method: 'GET', path: '/4', config: { plugins: { crumb: false } }, handler: function (request, reply) { + method: 'GET', path: '/4', config: { plugins: { crumb: false } }, handler: (request, reply) => { return reply.view('index', { title: 'test', @@ -72,58 +74,58 @@ describe('Crumb', function () { } }, { - method: 'POST', path: '/5', config: { payload: { output: 'stream' } }, handler: function (request, reply) { + method: 'POST', path: '/5', config: { payload: { output: 'stream' } }, handler: (request, reply) => { return reply('yo'); } }, { - method: 'GET', path: '/6', handler: function (request, reply) { + method: 'GET', path: '/6', handler: (request, reply) => { return reply.view('index'); } }, { - method: 'GET', path: '/7', handler: function (request, reply) { + method: 'GET', path: '/7', handler: (request, reply) => { return reply(null).redirect('/1'); } } ]); - server.register([{ register: vision }, { register: Crumb, options: { cookieOptions: { isSecure: true } } }], function (err) { + server.register([{ register: Vision }, { register: Crumb, options: { cookieOptions: { isSecure: true } } }], (err) => { expect(err).to.not.exist(); server.views(viewOptions); - server.inject({ method: 'GET', url: '/1' }, function (res) { + server.inject({ method: 'GET', url: '/1' }, (res) => { expect(res.statusCode).to.equal(200); - var header = res.headers['set-cookie']; + const header = res.headers['set-cookie']; expect(header.length).to.equal(1); expect(header[0]).to.contain('Secure'); - var cookie = header[0].match(/crumb=([^\x00-\x20\"\,\;\\\x7F]*)/); + const cookie = header[0].match(/crumb=([^\x00-\x20\"\,\;\\\x7F]*)/); expect(res.result).to.equal('test

hi

' + cookie[1] + '

'); - server.inject({ method: 'POST', url: '/2', payload: '{ "key": "value", "crumb": "' + cookie[1] + '" }', headers: { cookie: 'crumb=' + cookie[1] } }, function (res) { + server.inject({ method: 'POST', url: '/2', payload: '{ "key": "value", "crumb": "' + cookie[1] + '" }', headers: { cookie: 'crumb=' + cookie[1] } }, (res2) => { - expect(res.result).to.equal('valid'); + expect(res2.result).to.equal('valid'); - server.inject({ method: 'POST', url: '/2', payload: '{ "key": "value", "crumb": "x' + cookie[1] + '" }', headers: { cookie: 'crumb=' + cookie[1] } }, function (res) { + server.inject({ method: 'POST', url: '/2', payload: '{ "key": "value", "crumb": "x' + cookie[1] + '" }', headers: { cookie: 'crumb=' + cookie[1] } }, (res3) => { - expect(res.statusCode).to.equal(403); + expect(res3.statusCode).to.equal(403); - server.inject({ method: 'POST', url: '/3', headers: { cookie: 'crumb=' + cookie[1] } }, function (res) { + server.inject({ method: 'POST', url: '/3', headers: { cookie: 'crumb=' + cookie[1] } }, (res4) => { - expect(res.statusCode).to.equal(403); + expect(res4.statusCode).to.equal(403); - server.inject({ method: 'GET', url: '/4' }, function (res) { + server.inject({ method: 'GET', url: '/4' }, (res5) => { - expect(res.result).to.equal('test

hi

'); + expect(res5.result).to.equal('test

hi

'); - var TestStream = function (opt) { + const TestStream = function (opt) { Stream.Readable.call(this, opt); this._max = 2; @@ -132,44 +134,44 @@ describe('Crumb', function () { Hoek.inherits(TestStream, Stream.Readable); - TestStream.prototype._read = function () { + TestStream.prototype._read = () => { - var i = this._index++; + const i = this._index++; if (i > this._max) { this.push(null); } else { - var str = '' + i; - var buf = new Buffer(str, 'ascii'); + const str = '' + i; + const buf = new Buffer(str, 'ascii'); this.push(buf); } }; - server.inject({ method: 'POST', url: '/5', payload: new TestStream(), headers: { 'content-type': 'application/octet-stream', 'content-disposition': 'attachment; filename="test.txt"' }, simulate: { end: true } }, function (res) { + server.inject({ method: 'POST', url: '/5', payload: new TestStream(), headers: { 'content-type': 'application/octet-stream', 'content-disposition': 'attachment; filename="test.txt"' }, simulate: { end: true } }, (res6) => { - expect(res.statusCode).to.equal(403); + expect(res6.statusCode).to.equal(403); - server.inject({ method: 'GET', url: '/6' }, function (res) { + server.inject({ method: 'GET', url: '/6' }, (res7) => { - var header = res.headers['set-cookie']; - expect(header.length).to.equal(1); - expect(header[0]).to.contain('Secure'); + const header2 = res7.headers['set-cookie']; + expect(header2.length).to.equal(1); + expect(header2[0]).to.contain('Secure'); - var cookie = header[0].match(/crumb=([^\x00-\x20\"\,\;\\\x7F]*)/); - expect(res.result).to.equal('

' + cookie[1] + '

'); + const cookie2 = header2[0].match(/crumb=([^\x00-\x20\"\,\;\\\x7F]*)/); + expect(res7.result).to.equal('

' + cookie2[1] + '

'); - server.inject({ method: 'GET', url: '/7' }, function (res) { + server.inject({ method: 'GET', url: '/7' }, (res8) => { - var cookie = res.headers['set-cookie'].toString(); - expect(cookie).to.contain('crumb'); + const cookie3 = res8.headers['set-cookie'].toString(); + expect(cookie3).to.contain('crumb'); - var headers = {}; + const headers = {}; headers.origin = 'http://127.0.0.1'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { + server.inject({ method: 'GET', url: '/1', headers: headers }, (res9) => { - var cookie = res.headers['set-cookie'].toString(); - expect(cookie).to.contain('crumb'); + const cookie4 = res9.headers['set-cookie'].toString(); + expect(cookie4).to.contain('crumb'); done(); }); @@ -184,12 +186,12 @@ describe('Crumb', function () { }); }); - it('Does not add crumb to view context when "addToViewContext" option set to false', function (done) { + it('Does not add crumb to view context when "addToViewContext" option set to false', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection(); - var viewOptions = { + const viewOptions = { path: __dirname + '/templates', engines: { html: require('handlebars') @@ -197,7 +199,7 @@ describe('Crumb', function () { }; server.route({ - method: 'GET', path: '/1', handler: function (request, reply) { + method: 'GET', path: '/1', handler: (request, reply) => { expect(request.plugins.crumb).to.exist(); expect(request.server.plugins.crumb.generate).to.exist(); @@ -209,13 +211,13 @@ describe('Crumb', function () { } }); - server.register([{ register: vision }, { register: Crumb, options: { cookieOptions: { isSecure: true }, addToViewContext: false } }], function (err) { + server.register([{ register: Vision }, { register: Crumb, options: { cookieOptions: { isSecure: true }, addToViewContext: false } }], (err) => { expect(err).to.not.exist(); server.views(viewOptions); - server.inject({ method: 'GET', url: '/1' }, function (res) { + server.inject({ method: 'GET', url: '/1' }, (res) => { expect(res.result).to.equal('test

hi

'); done(); @@ -223,12 +225,12 @@ describe('Crumb', function () { }); }); - it('Works without specifying plugin options', function (done) { + it('Works without specifying plugin options', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection(); - var viewOptions = { + const viewOptions = { path: __dirname + '/templates', engines: { html: require('handlebars') @@ -236,7 +238,7 @@ describe('Crumb', function () { }; server.route({ - method: 'GET', path: '/1', handler: function (request, reply) { + method: 'GET', path: '/1', handler: (request, reply) => { expect(request.plugins.crumb).to.exist(); expect(request.server.plugins.crumb.generate).to.exist(); @@ -248,19 +250,19 @@ describe('Crumb', function () { } }); - server.register([{ register: vision }, { register: Crumb, options: null }], function (err) { + server.register([{ register: Vision }, { register: Crumb, options: null }], (err) => { expect(err).to.not.exist(); server.views(viewOptions); - server.inject({ method: 'GET', url: '/1' }, function (res) { + server.inject({ method: 'GET', url: '/1' }, (res) => { - var header = res.headers['set-cookie']; + const header = res.headers['set-cookie']; expect(header.length).to.equal(1); - var cookie = header[0].match(/crumb=([^\x00-\x20\"\,\;\\\x7F]*)/); + const cookie = header[0].match(/crumb=([^\x00-\x20\"\,\;\\\x7F]*)/); expect(res.result).to.equal('test

hi

' + cookie[1] + '

'); done(); @@ -268,9 +270,9 @@ describe('Crumb', function () { }); }); - it('should fail to register with bad options', function (done) { + it('should fail to register with bad options', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection(); server.register({ @@ -278,7 +280,7 @@ describe('Crumb', function () { options: { foo: 'bar' } - }, function (err) { + }, (err) => { expect(err).to.exist(); expect(err.name).to.equal('ValidationError'); @@ -287,12 +289,12 @@ describe('Crumb', function () { }); }); - it('route uses crumb when route.config.plugins.crumb set to true and autoGenerate set to false', function (done) { + it('route uses crumb when route.config.plugins.crumb set to true and autoGenerate set to false', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection(); - var viewOptions = { + const viewOptions = { path: __dirname + '/templates', engines: { html: require('handlebars') @@ -301,9 +303,9 @@ describe('Crumb', function () { server.route([ { - method: 'GET', path: '/1', handler: function (request, reply) { + method: 'GET', path: '/1', handler: (request, reply) => { - var crumb = request.plugins.crumb; + const crumb = request.plugins.crumb; expect(crumb).to.not.exist(); @@ -311,25 +313,25 @@ describe('Crumb', function () { } }, { - method: 'GET', path: '/2', config: { plugins: { crumb: true } }, handler: function (request, reply) { + method: 'GET', path: '/2', config: { plugins: { crumb: true } }, handler: (request, reply) => { return reply('hola'); } } ]); - server.register([{ register: vision }, { register: Crumb, options: { autoGenerate: false } }], function (err) { + server.register([{ register: Vision }, { register: Crumb, options: { autoGenerate: false } }], (err) => { expect(err).to.not.exist(); server.views(viewOptions); - server.inject({ method: 'GET', url: '/1' }, function () { + server.inject({ method: 'GET', url: '/1' }, () => { - server.inject({ method: 'GET', url: '/2' }, function (res) { + server.inject({ method: 'GET', url: '/2' }, (res) => { - var header = res.headers['set-cookie']; + const header = res.headers['set-cookie']; expect(header.length).to.equal(1); done(); }); @@ -337,25 +339,25 @@ describe('Crumb', function () { }); }); - it('fails validation when no payload provided and not using restful mode', function (done) { + it('fails validation when no payload provided and not using restful mode', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection(); server.route([ { - method: 'POST', path: '/1', handler: function (request, reply) { + method: 'POST', path: '/1', handler: (request, reply) => { return reply('test'); } } ]); - server.register([{ register: Crumb }], function (err) { + server.register([{ register: Crumb }], (err) => { expect(err).to.not.exist(); - var headers = {}; + const headers = {}; headers['X-API-Token'] = 'test'; - server.inject({ method: 'POST', url: '/1', headers: headers }, function (res) { + server.inject({ method: 'POST', url: '/1', headers: headers }, (res) => { expect(res.statusCode).to.equal(403); done(); @@ -363,195 +365,109 @@ describe('Crumb', function () { }); }); - it('does not validate crumb when "skip" option returns true', function (done) { + it('does not validate crumb when "skip" option returns true', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection(); server.route([ { - method: 'POST', path: '/1', handler: function (request, reply) { + method: 'POST', path: '/1', handler: (request, reply) => { return reply('test'); } } ]); - var skip = function (request, reply) { + const skip = (request) => { return request.headers['x-api-token'] === 'test'; }; - server.register([{ register: Crumb, options: { skip: skip } }], function (err) { + server.register([{ register: Crumb, options: { skip: skip } }], (err) => { expect(err).to.not.exist(); - var headers = {}; + const headers = {}; headers['X-API-Token'] = 'test'; - server.inject({ method: 'POST', url: '/1', headers: headers }, function (res) { + server.inject({ method: 'POST', url: '/1', headers: headers }, (res) => { expect(res.statusCode).to.equal(200); - var header = res.headers['set-cookie']; + const header = res.headers['set-cookie']; expect(header).to.not.exist(); done(); }); }); }); - it('ensures crumb "skip" option is a function', function (done) { + it('ensures crumb "skip" option is a function', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection(); server.route([ { - method: 'POST', path: '/1', handler: function (request, reply) { + method: 'POST', path: '/1', handler: (request, reply) => { return reply('test'); } } ]); - var skip = true; - - server.register([{ register: vision }, { register: Crumb, options: { skip: skip } }], function (err) { - - expect(err).to.exist(); - done(); - }); - }); - - it('does not allow "*" for allowOrigins setting', function (done) { - - var server = new Hapi.Server(); - server.connection(); + const skip = true; - server.register([{ register: Crumb, options: { allowOrigins: ['*'] } }], function (err) { + server.register([{ register: Vision }, { register: Crumb, options: { skip: skip } }], (err) => { expect(err).to.exist(); - expect(err.name).to.equal('ValidationError'); - expect(err.message).to.equal('child "allowOrigins" fails because ["allowOrigins" at position 0 contains an excluded value]'); done(); }); }); - it('does not set crumb cookie insecurely', function (done) { + it('does not set crumb cookie insecurely', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection({ host: 'localhost', port: 80, routes: { cors: true } }); - server.route({ method: 'GET', path: '/1', handler: function (request, reply) { + server.route({ method: 'GET', path: '/1', config: { cors: false }, handler: (request, reply) => { return reply('test'); } }); + server.route({ method: 'GET', path: '/2', handler: (request, reply) => { - server.register([{ register: Crumb, options: null }], function (err) { - - expect(err).to.not.exist(); - - var headers = {}; - headers.host = 'localhost:80'; - - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header[0]).to.contain('crumb'); - - delete headers.host; - - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - headers.origin = 'http://127.0.0.1'; - - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); - - done(); - }); - }); - }); - }); - - it('does not set crumb cookie insecurely using https', function (done) { - - var options = { - host: 'localhost', - port: 443, - routes: { - cors: true - }, - tls: { - key: '-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA0UqyXDCqWDKpoNQQK/fdr0OkG4gW6DUafxdufH9GmkX/zoKz\ng/SFLrPipzSGINKWtyMvo7mPjXqqVgE10LDI3VFV8IR6fnART+AF8CW5HMBPGt/s\nfQW4W4puvBHkBxWSW1EvbecgNEIS9hTGvHXkFzm4xJ2e9DHp2xoVAjREC73B7JbF\nhc5ZGGchKw+CFmAiNysU0DmBgQcac0eg2pWoT+YGmTeQj6sRXO67n2xy/hA1DuN6\nA4WBK3wM3O4BnTG0dNbWUEbe7yAbV5gEyq57GhJIeYxRvveVDaX90LoAqM4cUH06\n6rciON0UbDHV2LP/JaH5jzBjUyCnKLLo5snlbwIDAQABAoIBAQDJm7YC3pJJUcxb\nc8x8PlHbUkJUjxzZ5MW4Zb71yLkfRYzsxrTcyQA+g+QzA4KtPY8XrZpnkgm51M8e\n+B16AcIMiBxMC6HgCF503i16LyyJiKrrDYfGy2rTK6AOJQHO3TXWJ3eT3BAGpxuS\n12K2Cq6EvQLCy79iJm7Ks+5G6EggMZPfCVdEhffRm2Epl4T7LpIAqWiUDcDfS05n\nNNfAGxxvALPn+D+kzcSF6hpmCVrFVTf9ouhvnr+0DpIIVPwSK/REAF3Ux5SQvFuL\njPmh3bGwfRtcC5d21QNrHdoBVSN2UBLmbHUpBUcOBI8FyivAWJhRfKnhTvXMFG8L\nwaXB51IZAoGBAP/E3uz6zCyN7l2j09wmbyNOi1AKvr1WSmuBJveITouwblnRSdvc\nsYm4YYE0Vb94AG4n7JIfZLKtTN0xvnCo8tYjrdwMJyGfEfMGCQQ9MpOBXAkVVZvP\ne2k4zHNNsfvSc38UNSt7K0HkVuH5BkRBQeskcsyMeu0qK4wQwdtiCoBDAoGBANF7\nFMppYxSW4ir7Jvkh0P8bP/Z7AtaSmkX7iMmUYT+gMFB5EKqFTQjNQgSJxS/uHVDE\nSC5co8WGHnRk7YH2Pp+Ty1fHfXNWyoOOzNEWvg6CFeMHW2o+/qZd4Z5Fep6qCLaa\nFvzWWC2S5YslEaaP8DQ74aAX4o+/TECrxi0z2lllAoGAdRB6qCSyRsI/k4Rkd6Lv\nw00z3lLMsoRIU6QtXaZ5rN335Awyrfr5F3vYxPZbOOOH7uM/GDJeOJmxUJxv+cia\nPQDflpPJZU4VPRJKFjKcb38JzO6C3Gm+po5kpXGuQQA19LgfDeO2DNaiHZOJFrx3\nm1R3Zr/1k491lwokcHETNVkCgYBPLjrZl6Q/8BhlLrG4kbOx+dbfj/euq5NsyHsX\n1uI7bo1Una5TBjfsD8nYdUr3pwWltcui2pl83Ak+7bdo3G8nWnIOJ/WfVzsNJzj7\n/6CvUzR6sBk5u739nJbfgFutBZBtlSkDQPHrqA7j3Ysibl3ZIJlULjMRKrnj6Ans\npCDwkQKBgQCM7gu3p7veYwCZaxqDMz5/GGFUB1My7sK0hcT7/oH61yw3O8pOekee\nuctI1R3NOudn1cs5TAy/aypgLDYTUGQTiBRILeMiZnOrvQQB9cEf7TFgDoRNCcDs\nV/ZWiegVB/WY7H0BkCekuq5bHwjgtJTpvHGqQ9YD7RhE8RSYOhdQ/Q==\n-----END RSA PRIVATE KEY-----\n', - cert: '-----BEGIN CERTIFICATE-----\nMIIDBjCCAe4CCQDvLNml6smHlTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJV\nUzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\ncyBQdHkgTHRkMB4XDTE0MDEyNTIxMjIxOFoXDTE1MDEyNTIxMjIxOFowRTELMAkG\nA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0\nIFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nANFKslwwqlgyqaDUECv33a9DpBuIFug1Gn8Xbnx/RppF/86Cs4P0hS6z4qc0hiDS\nlrcjL6O5j416qlYBNdCwyN1RVfCEen5wEU/gBfAluRzATxrf7H0FuFuKbrwR5AcV\nkltRL23nIDRCEvYUxrx15Bc5uMSdnvQx6dsaFQI0RAu9weyWxYXOWRhnISsPghZg\nIjcrFNA5gYEHGnNHoNqVqE/mBpk3kI+rEVzuu59scv4QNQ7jegOFgSt8DNzuAZ0x\ntHTW1lBG3u8gG1eYBMquexoSSHmMUb73lQ2l/dC6AKjOHFB9Ouq3IjjdFGwx1diz\n/yWh+Y8wY1Mgpyiy6ObJ5W8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAoSc6Skb4\ng1e0ZqPKXBV2qbx7hlqIyYpubCl1rDiEdVzqYYZEwmst36fJRRrVaFuAM/1DYAmT\nWMhU+yTfA+vCS4tql9b9zUhPw/IDHpBDWyR01spoZFBF/hE1MGNpCSXXsAbmCiVf\naxrIgR2DNketbDxkQx671KwF1+1JOMo9ffXp+OhuRo5NaGIxhTsZ+f/MA4y084Aj\nDI39av50sTRTWWShlN+J7PtdQVA5SZD97oYbeUeL7gI18kAJww9eUdmT0nEjcwKs\nxsQT1fyKbo7AlZBY4KSlUMuGnn0VnAsB9b+LxtXlDfnjyM8bVQx1uAfRo0DO8p/5\n3J5DTjAU55deBQ==\n-----END CERTIFICATE-----\n' - } - }; + return reply('test'); + } }); + server.route({ method: 'GET', path: '/3', config: { cors: { origin: ['http://127.0.0.1'] } }, handler: (request, reply) => { - var server = new Hapi.Server(); - server.connection(options); - server.route([ - { - method: 'GET', path: '/1', handler: function (request, reply) { + return reply('test'); + } }); - return reply('test'); - } - } - ]); - server.register([{ register: Crumb, options: null }], function (err) { + server.register([{ register: Crumb, options: null }], (err) => { expect(err).to.not.exist(); - server.inject({ method: 'GET', url: '/1', headers: { host: 'localhost:443' } }, function (res) { + const headers = {}; - var header = res.headers['set-cookie']; - expect(header[0]).to.contain('crumb'); - - server.inject({ method: 'GET', url: '/1' }, function (res) { - - expect(res.headers['set-cookie']).to.not.exist(); - done(); - }); - }); - }); - }); + server.inject({ method: 'GET', url: '/1', headers: headers }, (res) => { - it('does set crumb cookie if allowOrigins set and CORS enabled', function (done) { - - var server = new Hapi.Server(); - server.connection({ host: 'localhost', port: 80, routes: { cors: true } }); - server.route([ - { - method: 'GET', path: '/1', handler: function (request, reply) { - - return reply('test'); - } - } - ]); - server.register([{ register: Crumb, options: { allowOrigins: ['http://127.0.0.1'] } }], function (err) { - - expect(err).to.not.exist(); - var headers = {}; - headers.origin = 'http://127.0.0.1'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; + const header = res.headers['set-cookie']; expect(header[0]).to.contain('crumb'); - headers.origin = 'http://127.0.0.2'; + headers.origin = 'http://localhost'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { + server.inject({ method: 'GET', url: '/2', headers: headers }, (res2) => { - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); + const header2 = res2.headers['set-cookie']; + expect(header2[0]).to.contain('crumb'); - headers.origin = 'http://127.0.0.1:2000'; + headers.origin = 'http://127.0.0.1'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { + server.inject({ method: 'GET', url: '/3', headers: headers }, (res3) => { - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); + const header3 = res3.headers['set-cookie']; + expect(header3[0]).to.contain('crumb'); - delete headers.origin; + headers.origin = 'http://badsite.com'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { + server.inject({ method: 'GET', url: '/3', headers: headers }, (res4) => { - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); + const header4 = res4.headers['set-cookie']; + expect(header4).to.not.exist(); done(); }); @@ -561,173 +477,47 @@ describe('Crumb', function () { }); }); - it('does set crumb cookie if allowOrigins not set and CORS enabled with server.settings.cors.origin set', function (done) { + it('does not set crumb cookie insecurely using https', (done) => { - var server = new Hapi.Server(); - server.connection({ host: 'localhost', port: 80, routes: { cors: { origin: ['http://127.0.0.1'] } } }); - server.route([ - { - method: 'GET', path: '/1', handler: function (request, reply) { - - return reply('test'); - } + const options = { + host: 'localhost', + port: 443, + tls: { + key: '-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA0UqyXDCqWDKpoNQQK/fdr0OkG4gW6DUafxdufH9GmkX/zoKz\ng/SFLrPipzSGINKWtyMvo7mPjXqqVgE10LDI3VFV8IR6fnART+AF8CW5HMBPGt/s\nfQW4W4puvBHkBxWSW1EvbecgNEIS9hTGvHXkFzm4xJ2e9DHp2xoVAjREC73B7JbF\nhc5ZGGchKw+CFmAiNysU0DmBgQcac0eg2pWoT+YGmTeQj6sRXO67n2xy/hA1DuN6\nA4WBK3wM3O4BnTG0dNbWUEbe7yAbV5gEyq57GhJIeYxRvveVDaX90LoAqM4cUH06\n6rciON0UbDHV2LP/JaH5jzBjUyCnKLLo5snlbwIDAQABAoIBAQDJm7YC3pJJUcxb\nc8x8PlHbUkJUjxzZ5MW4Zb71yLkfRYzsxrTcyQA+g+QzA4KtPY8XrZpnkgm51M8e\n+B16AcIMiBxMC6HgCF503i16LyyJiKrrDYfGy2rTK6AOJQHO3TXWJ3eT3BAGpxuS\n12K2Cq6EvQLCy79iJm7Ks+5G6EggMZPfCVdEhffRm2Epl4T7LpIAqWiUDcDfS05n\nNNfAGxxvALPn+D+kzcSF6hpmCVrFVTf9ouhvnr+0DpIIVPwSK/REAF3Ux5SQvFuL\njPmh3bGwfRtcC5d21QNrHdoBVSN2UBLmbHUpBUcOBI8FyivAWJhRfKnhTvXMFG8L\nwaXB51IZAoGBAP/E3uz6zCyN7l2j09wmbyNOi1AKvr1WSmuBJveITouwblnRSdvc\nsYm4YYE0Vb94AG4n7JIfZLKtTN0xvnCo8tYjrdwMJyGfEfMGCQQ9MpOBXAkVVZvP\ne2k4zHNNsfvSc38UNSt7K0HkVuH5BkRBQeskcsyMeu0qK4wQwdtiCoBDAoGBANF7\nFMppYxSW4ir7Jvkh0P8bP/Z7AtaSmkX7iMmUYT+gMFB5EKqFTQjNQgSJxS/uHVDE\nSC5co8WGHnRk7YH2Pp+Ty1fHfXNWyoOOzNEWvg6CFeMHW2o+/qZd4Z5Fep6qCLaa\nFvzWWC2S5YslEaaP8DQ74aAX4o+/TECrxi0z2lllAoGAdRB6qCSyRsI/k4Rkd6Lv\nw00z3lLMsoRIU6QtXaZ5rN335Awyrfr5F3vYxPZbOOOH7uM/GDJeOJmxUJxv+cia\nPQDflpPJZU4VPRJKFjKcb38JzO6C3Gm+po5kpXGuQQA19LgfDeO2DNaiHZOJFrx3\nm1R3Zr/1k491lwokcHETNVkCgYBPLjrZl6Q/8BhlLrG4kbOx+dbfj/euq5NsyHsX\n1uI7bo1Una5TBjfsD8nYdUr3pwWltcui2pl83Ak+7bdo3G8nWnIOJ/WfVzsNJzj7\n/6CvUzR6sBk5u739nJbfgFutBZBtlSkDQPHrqA7j3Ysibl3ZIJlULjMRKrnj6Ans\npCDwkQKBgQCM7gu3p7veYwCZaxqDMz5/GGFUB1My7sK0hcT7/oH61yw3O8pOekee\nuctI1R3NOudn1cs5TAy/aypgLDYTUGQTiBRILeMiZnOrvQQB9cEf7TFgDoRNCcDs\nV/ZWiegVB/WY7H0BkCekuq5bHwjgtJTpvHGqQ9YD7RhE8RSYOhdQ/Q==\n-----END RSA PRIVATE KEY-----\n', + cert: '-----BEGIN CERTIFICATE-----\nMIIDBjCCAe4CCQDvLNml6smHlTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJV\nUzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\ncyBQdHkgTHRkMB4XDTE0MDEyNTIxMjIxOFoXDTE1MDEyNTIxMjIxOFowRTELMAkG\nA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0\nIFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nANFKslwwqlgyqaDUECv33a9DpBuIFug1Gn8Xbnx/RppF/86Cs4P0hS6z4qc0hiDS\nlrcjL6O5j416qlYBNdCwyN1RVfCEen5wEU/gBfAluRzATxrf7H0FuFuKbrwR5AcV\nkltRL23nIDRCEvYUxrx15Bc5uMSdnvQx6dsaFQI0RAu9weyWxYXOWRhnISsPghZg\nIjcrFNA5gYEHGnNHoNqVqE/mBpk3kI+rEVzuu59scv4QNQ7jegOFgSt8DNzuAZ0x\ntHTW1lBG3u8gG1eYBMquexoSSHmMUb73lQ2l/dC6AKjOHFB9Ouq3IjjdFGwx1diz\n/yWh+Y8wY1Mgpyiy6ObJ5W8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAoSc6Skb4\ng1e0ZqPKXBV2qbx7hlqIyYpubCl1rDiEdVzqYYZEwmst36fJRRrVaFuAM/1DYAmT\nWMhU+yTfA+vCS4tql9b9zUhPw/IDHpBDWyR01spoZFBF/hE1MGNpCSXXsAbmCiVf\naxrIgR2DNketbDxkQx671KwF1+1JOMo9ffXp+OhuRo5NaGIxhTsZ+f/MA4y084Aj\nDI39av50sTRTWWShlN+J7PtdQVA5SZD97oYbeUeL7gI18kAJww9eUdmT0nEjcwKs\nxsQT1fyKbo7AlZBY4KSlUMuGnn0VnAsB9b+LxtXlDfnjyM8bVQx1uAfRo0DO8p/5\n3J5DTjAU55deBQ==\n-----END CERTIFICATE-----\n' } - ]); - server.register([{ register: Crumb, options: null }], function (err) { - - expect(err).to.not.exist(); - var headers = {}; - headers.origin = 'http://127.0.0.1'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header[0]).to.contain('crumb'); - - headers.origin = 'http://127.0.0.2'; - - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); - - headers.origin = 'http://127.0.0.1:2000'; - - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); - - delete headers.origin; - - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); - - done(); - }); - }); - }); - }); - }); - }); - - it('does not set crumb cookie if allowOrigins not set and CORS set to "*"', function (done) { + }; - var server = new Hapi.Server(); - server.connection({ host: 'localhost', port: 80, routes: { cors: { origin: ['*'] } } }); + const server = new Hapi.Server(); + server.connection(options); server.route([ { - method: 'GET', path: '/1', handler: function (request, reply) { + method: 'GET', path: '/1', handler: (request, reply) => { return reply('test'); } } ]); - - server.register([{ register: Crumb, options: null }], function (err) { + server.register([{ register: Crumb, options: null }], (err) => { expect(err).to.not.exist(); - var headers = {}; - headers.origin = 'http://127.0.0.1'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); - - done(); - }); - }); - }); - - it('checks port for allowOrigins setting', function (done) { - - var server = new Hapi.Server(); - server.connection({ host: 'localhost', port: 80, routes: { cors: true } }); - server.route([ - { - method: 'GET', path: '/1', handler: function (request, reply) { - - return reply('test'); - } - } - ]); - server.register([{ register: Crumb, options: { allowOrigins: ['http://127.0.0.1:2000'] } }], function (err) { - expect(err).to.not.exist(); - var headers = {}; - headers.origin = 'http://127.0.0.1:2000'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { + server.inject({ method: 'GET', url: '/1', headers: { host: 'localhost:443' } }, (res) => { - var header = res.headers['set-cookie']; + const header = res.headers['set-cookie']; expect(header[0]).to.contain('crumb'); - headers.origin = 'http://127.0.0.1:1000'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); - - headers.origin = 'http://127.0.0.1'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); - - done(); - }); - }); + done(); }); }); }); - it('parses wildcards in allowOrigins setting', function (done) { - - var server = new Hapi.Server(); - server.connection({ host: 'localhost', port: 80, routes: { cors: true } }); - server.route([ - { - method: 'GET', path: '/1', handler: function (request, reply) { - - return reply('test'); - } - } - ]); - server.register([{ register: Crumb, options: { allowOrigins: ['http://127.0.0.1:*', 'http://*.test.com'] } }], function (err) { - - expect(err).to.not.exist(); - var headers = {}; - headers.origin = 'http://127.0.0.1:2000'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header[0]).to.contain('crumb'); - - headers.origin = 'http://*.test.com'; - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header[0]).to.contain('crumb'); - - headers.origin = 'http://foo.tesc.com'; - - server.inject({ method: 'GET', url: '/1', headers: headers }, function (res) { - - var header = res.headers['set-cookie']; - expect(header).to.not.exist(); - - done(); - }); - }); - }); - }); - }); - it('validates crumb with X-CSRF-Token header', function (done) { + it('validates crumb with X-CSRF-Token header', (done) => { - var server = new Hapi.Server(); + const server = new Hapi.Server(); server.connection(); - var viewOptions = { + const viewOptions = { path: __dirname + '/templates', engines: { html: require('handlebars') @@ -736,7 +526,7 @@ describe('Crumb', function () { server.route([ { - method: 'GET', path: '/1', handler: function (request, reply) { + method: 'GET', path: '/1', handler: (request, reply) => { expect(request.plugins.crumb).to.exist(); expect(request.server.plugins.crumb.generate).to.exist(); @@ -748,47 +538,47 @@ describe('Crumb', function () { } }, { - method: 'POST', path: '/2', handler: function (request, reply) { + method: 'POST', path: '/2', handler: (request, reply) => { expect(request.payload).to.deep.equal({ key: 'value' }); return reply('valid'); } }, { - method: 'POST', path: '/3', config: { payload: { output: 'stream' } }, handler: function (request, reply) { + method: 'POST', path: '/3', config: { payload: { output: 'stream' } }, handler: (request, reply) => { return reply('never'); } }, { - method: 'PUT', path: '/4', handler: function (request, reply) { + method: 'PUT', path: '/4', handler: (request, reply) => { expect(request.payload).to.deep.equal({ key: 'value' }); return reply('valid'); } }, { - method: 'PATCH', path: '/5', handler: function (request, reply) { + method: 'PATCH', path: '/5', handler: (request, reply) => { expect(request.payload).to.deep.equal({ key: 'value' }); return reply('valid'); } }, { - method: 'DELETE', path: '/6', handler: function (request, reply) { + method: 'DELETE', path: '/6', handler: (request, reply) => { return reply('valid'); } }, { - method: 'POST', path: '/7', config: { plugins: { crumb: false } }, handler: function (request, reply) { + method: 'POST', path: '/7', config: { plugins: { crumb: false } }, handler: (request, reply) => { expect(request.payload).to.deep.equal({ key: 'value' }); return reply('valid'); } }, { - method: 'POST', path: '/8', config: { plugins: { crumb: { restful: false, source: 'payload' } } }, handler: function (request, reply) { + method: 'POST', path: '/8', config: { plugins: { crumb: { restful: false, source: 'payload' } } }, handler: (request, reply) => { expect(request.payload).to.deep.equal({ key: 'value' }); return reply('valid'); @@ -797,76 +587,76 @@ describe('Crumb', function () { ]); - server.register([{ register: vision }, { register: Crumb, options: { restful: true, cookieOptions: { isSecure: true } } }], function (err) { + server.register([{ register: Vision }, { register: Crumb, options: { restful: true, cookieOptions: { isSecure: true } } }], (err) => { expect(err).to.not.exist(); server.views(viewOptions); - server.inject({ method: 'GET', url: '/1' }, function (res) { + server.inject({ method: 'GET', url: '/1' }, (res) => { - var header = res.headers['set-cookie']; + const header = res.headers['set-cookie']; expect(header.length).to.equal(1); expect(header[0]).to.contain('Secure'); - var cookie = header[0].match(/crumb=([^\x00-\x20\"\,\;\\\x7F]*)/); + const cookie = header[0].match(/crumb=([^\x00-\x20\"\,\;\\\x7F]*)/); - var validHeader = {}; + const validHeader = {}; validHeader.cookie = 'crumb=' + cookie[1]; validHeader['x-csrf-token'] = cookie[1]; - var invalidHeader = {}; + const invalidHeader = {}; invalidHeader.cookie = 'crumb=' + cookie[1]; invalidHeader['x-csrf-token'] = 'x' + cookie[1]; expect(res.result).to.equal('test

hi

' + cookie[1] + '

'); - server.inject({ method: 'POST', url: '/2', payload: '{ "key": "value" }', headers: validHeader }, function (res) { + server.inject({ method: 'POST', url: '/2', payload: '{ "key": "value" }', headers: validHeader }, (res2) => { - expect(res.result).to.equal('valid'); + expect(res2.result).to.equal('valid'); - server.inject({ method: 'POST', url: '/2', payload: '{ "key": "value" }', headers: invalidHeader }, function (res) { + server.inject({ method: 'POST', url: '/2', payload: '{ "key": "value" }', headers: invalidHeader }, (res3) => { - expect(res.statusCode).to.equal(403); + expect(res3.statusCode).to.equal(403); - server.inject({ method: 'POST', url: '/3', headers: { cookie: 'crumb=' + cookie[1] } }, function (res) { + server.inject({ method: 'POST', url: '/3', headers: { cookie: 'crumb=' + cookie[1] } }, (res4) => { - expect(res.statusCode).to.equal(403); + expect(res4.statusCode).to.equal(403); - server.inject({ method: 'PUT', url: '/4', payload: '{ "key": "value" }', headers: validHeader }, function (res) { + server.inject({ method: 'PUT', url: '/4', payload: '{ "key": "value" }', headers: validHeader }, (res5) => { - expect(res.result).to.equal('valid'); + expect(res5.result).to.equal('valid'); - server.inject({ method: 'PUT', url: '/4', payload: '{ "key": "value" }', headers: invalidHeader }, function (res) { + server.inject({ method: 'PUT', url: '/4', payload: '{ "key": "value" }', headers: invalidHeader }, (res6) => { - expect(res.statusCode).to.equal(403); + expect(res6.statusCode).to.equal(403); - server.inject({ method: 'PATCH', url: '/5', payload: '{ "key": "value" }', headers: validHeader }, function (res) { + server.inject({ method: 'PATCH', url: '/5', payload: '{ "key": "value" }', headers: validHeader }, (res7) => { - expect(res.result).to.equal('valid'); + expect(res7.result).to.equal('valid'); - server.inject({ method: 'PATCH', url: '/5', payload: '{ "key": "value" }', headers: invalidHeader }, function (res) { + server.inject({ method: 'PATCH', url: '/5', payload: '{ "key": "value" }', headers: invalidHeader }, (res8) => { - expect(res.statusCode).to.equal(403); + expect(res8.statusCode).to.equal(403); - server.inject({ method: 'DELETE', url: '/6', headers: validHeader }, function (res) { + server.inject({ method: 'DELETE', url: '/6', headers: validHeader }, (res9) => { - expect(res.result).to.equal('valid'); + expect(res9.result).to.equal('valid'); - server.inject({ method: 'DELETE', url: '/6', headers: invalidHeader }, function (res) { + server.inject({ method: 'DELETE', url: '/6', headers: invalidHeader }, (res10) => { - expect(res.statusCode).to.equal(403); + expect(res10.statusCode).to.equal(403); - server.inject({ method: 'POST', url: '/7', payload: '{ "key": "value" }' }, function (res) { + server.inject({ method: 'POST', url: '/7', payload: '{ "key": "value" }' }, (res11) => { - expect(res.result).to.equal('valid'); + expect(res11.result).to.equal('valid'); - var payload = { key: 'value', crumb: cookie[1] }; + const payload = { key: 'value', crumb: cookie[1] }; delete validHeader['x-csrf-token']; - server.inject({ method: 'POST', url: '/8', payload: JSON.stringify(payload), headers: validHeader }, function (res) { + server.inject({ method: 'POST', url: '/8', payload: JSON.stringify(payload), headers: validHeader }, (res12) => { - expect(res.result).to.equal('valid'); + expect(res12.result).to.equal('valid'); done(); }); });