From 567a068888936c161d8a9795c13bbf8eb9da3270 Mon Sep 17 00:00:00 2001 From: Mike Kusold Date: Thu, 18 Jan 2018 21:45:47 -0700 Subject: [PATCH 1/7] t make compatible with hapi 17 --- lib/index.js | 104 +++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/lib/index.js b/lib/index.js index 07d1ed9..a5d3c9d 100755 --- a/lib/index.js +++ b/lib/index.js @@ -2,115 +2,115 @@ var Boom = require('boom'); var Hoek = require('hoek'); -var jwt = require('jsonwebtoken'); +var jwt = require('jsonwebtoken'); var Joi = require('joi'); var optionsSchema = Joi.object().keys({ - key: Joi.alternatives().try(Joi.binary(),Joi.func()).required(), + key: Joi.alternatives().try(Joi.binary(), Joi.func()).required(), validateFunc: Joi.func(), algorithms: Joi.array().items(Joi.string()), - audience: Joi.alternatives().try(Joi.string(),Joi.array().items(Joi.string())), - issuer: Joi.alternatives().try(Joi.string(),Joi.array().items(Joi.string())), + audience: Joi.alternatives().try(Joi.string(), Joi.array().items(Joi.string())), + issuer: Joi.alternatives().try(Joi.string(), Joi.array().items(Joi.string())), subject: Joi.string() }).label('jwt auth strategy options'); // Declare internals var internals = {}; - -exports.register = function (server, options, next) { - +function register(server, options) { server.auth.scheme('jwt', internals.implementation); - next(); -}; - -exports.register.attributes = { - pkg: require('../package.json') }; function isFunction(functionToCheck) { - return Object.prototype.toString.call(functionToCheck) === '[object Function]'; + const objectProto = Object.prototype.toString.call(functionToCheck); + return objectProto === '[object Function]' || objectProto === '[object AsyncFunction]'; } internals.implementation = function (server, options) { var validationResult = Joi.validate(options, optionsSchema); - if (validationResult.error){ + if (validationResult.error) { throw new Error(validationResult.error.message); } var settings = Hoek.clone(options); var scheme = { - authenticate: function (request, reply) { + authenticate: async function (request, h) { var req = request.raw.req; var authorization = req.headers.authorization; if (!authorization) { - return reply(Boom.unauthorized(null, 'Bearer')); + throw Boom.unauthorized(null, 'Bearer'); } var parts = authorization.split(/\s+/); if (parts.length !== 2) { - return reply(Boom.badRequest('Bad HTTP authentication header format', 'Bearer')); + throw Boom.badRequest('Bad HTTP authentication header format', 'Bearer'); } if (parts[0].toLowerCase() !== 'bearer') { - return reply(Boom.unauthorized(null, 'Bearer')); + throw Boom.unauthorized(null, 'Bearer'); } - if(parts[1].split('.').length !== 3) { - return reply(Boom.badRequest('Bad HTTP authentication header format', 'Bearer')); + if (parts[1].split('.').length !== 3) { + throw Boom.badRequest('Bad HTTP authentication header format', 'Bearer'); } var token = parts[1]; var getKey = isFunction(settings.key) ? settings.key : - function(req, token, callback) { callback(null, settings.key); }; - - getKey(request, token, function(err, key, extraInfo){ - if (err) { return reply(Boom.wrap(err)); } - // handle err - jwt.verify(token, key, settings, function(err, decoded) { - - if(err) { - return reply(Boom.unauthorized( 'JSON Web Token validation failed: ' + err.message, 'Bearer')); - } - - if (!settings.validateFunc) { - return reply.continue({ credentials: decoded }); - } - - settings.validateFunc(decoded, extraInfo, function (err, isValid, credentials) { + function (req, token) { return settings.key; }; - credentials = credentials || null; + let keyResult; + try { + keyResult = await getKey(request, token); + } catch (err) { + throw err; + } + const { key, extraInfo } = keyResult; - if (err) { - return reply(err, null, { credentials: credentials, log: { tags: ['auth', 'jwt'], data: err } }); - } + let decoded; + try { + decoded = jwt.verify(token, key, settings); + } catch (err) { + throw Boom.unauthorized('JSON Web Token validation failed: ' + err.message, 'Bearer'); + } - if (!isValid) { - return reply(Boom.unauthorized('Invalid token', 'Bearer'), null, { credentials: credentials }); - } + if (!settings.validateFunc) { + return h.authenticated({ credentials: decoded }); + } - if (!credentials || typeof credentials !== 'object') { + let validateResult; + try { + validateResult = await settings.validateFunc(decoded, extraInfo); + } catch (err) { + throw err; + } - return reply(Boom.badImplementation('Bad credentials object received for jwt auth validation'), null, { log: { tags: 'credentials' } }); - } + const { isValid, credentials } = validateResult; - // Authenticated + if (!isValid) { + throw Boom.unauthorized('Invalid token', 'Bearer'); + } - return reply.continue({ credentials: credentials }); - }); + if (!credentials || typeof credentials !== 'object') { + throw Boom.badImplementation('Bad credentials object received for jwt auth validation'); + } - }); - }); + // Authenticated + return h.authenticated({ credentials: credentials }); } }; - return scheme; + return scheme; }; + +module.exports = { + pkg: require('../package.json'), + register, +} \ No newline at end of file From ce0f91919d50813e7a9932ddbfa77285aa515116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Diaz?= Date: Mon, 5 Feb 2018 17:04:38 -0300 Subject: [PATCH 2/7] Make tests work --- lib/index.js | 6 +- package.json | 11 +- test/dynamicKeys.tests.js | 117 +++--- test/index.js | 800 ++++++++++++++++---------------------- 4 files changed, 401 insertions(+), 533 deletions(-) diff --git a/lib/index.js b/lib/index.js index a5d3c9d..64dd566 100755 --- a/lib/index.js +++ b/lib/index.js @@ -29,7 +29,6 @@ function isFunction(functionToCheck) { internals.implementation = function (server, options) { var validationResult = Joi.validate(options, optionsSchema); - if (validationResult.error) { throw new Error(validationResult.error.message); } @@ -63,7 +62,7 @@ internals.implementation = function (server, options) { var getKey = isFunction(settings.key) ? settings.key : - function (req, token) { return settings.key; }; + function (req, token) { return { key: settings.key }; }; let keyResult; try { @@ -107,10 +106,9 @@ internals.implementation = function (server, options) { }; return scheme; - }; module.exports = { pkg: require('../package.json'), register, -} \ No newline at end of file +} diff --git a/package.json b/package.json index e69a2d8..bcf3d58 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "JWT" ], "engines": { - "node": ">=4.x.x" + "node": ">=8.x.x" }, "dependencies": { "boom": "2.x.x", @@ -21,14 +21,17 @@ "jsonwebtoken": "^5.4.1" }, "devDependencies": { - "code": "1.x.x", - "hapi": "11.x.x", - "lab": "5.x.x", + "code": "5.x.x", + "hapi": ">=17.x.x", + "lab": "15.x.x", "grunt": "0.4.x", "grunt-contrib-jshint": "0.11.x", "grunt-contrib-watch": "0.6.x", "grunt-bump": "0.1.x" }, + "peerDependencies": { + "hapi": ">=17.x.x" + }, "scripts": { "test": "make test-cov" }, diff --git a/test/dynamicKeys.tests.js b/test/dynamicKeys.tests.js index 66b7e7c..0eb79eb 100644 --- a/test/dynamicKeys.tests.js +++ b/test/dynamicKeys.tests.js @@ -37,106 +37,97 @@ describe('Dynamic Secret', function () { return 'Bearer ' + jwt.sign({username: username}, keys[username], options); }; - var tokenHandler = function (request, reply) { - reply(request.auth.credentials.username); + var tokenHandler = function (request, h) { + return request.auth.credentials.username; }; - var getKey = function(req, token, callback){ + var getKey = async function(req, token){ getKey.lastToken = token; var data = jwt.decode(token); - Hoek.nextTick(function(){ - callback(null, keys[data.username], info[data.username]); - })(); + + return { + key: keys[data.username], + extraInfo: info[data.username] + } }; - var validateFunc = function(decoded, extraInfo, callback){ + var validateFunc = function(decoded, extraInfo){ validateFunc.lastExtraInfo = extraInfo; - callback(null, true, decoded); + + return { + isValid: true, + credentials: decoded + }; }; - var errorGetKey = function(req, token, callback){ - callback(new Error('Failed')); + var errorGetKey = function(req, token){ + throw new Error('Failed'); }; - var boomErrorGetKey = function(req, token, callback){ - callback(Boom.forbidden('forbidden')); + var boomErrorGetKey = function(req, token){ + throw Boom.forbidden('forbidden'); }; var server = new Hapi.Server({ debug: false }); - server.connection(); - - before(function (done) { - server.register(require('../'), function (err) { - expect(err).to.not.exist; - server.auth.strategy('normalError', 'jwt', false, { key: errorGetKey }); - server.auth.strategy('boomError', 'jwt', false, { key: boomErrorGetKey }); - server.auth.strategy('default', 'jwt', false, { key: getKey, validateFunc: validateFunc }); - server.route([ - { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } }, - { method: 'POST', path: '/normalError', handler: tokenHandler, config: { auth: 'normalError' } }, - { method: 'POST', path: '/boomError', handler: tokenHandler, config: { auth: 'boomError' } } - ]); - - done(); - }); + + before(async function () { + await server.register(require('../')) + server.auth.strategy('normalError', 'jwt', { key: errorGetKey }); + server.auth.strategy('boomError', 'jwt', { key: boomErrorGetKey }); + server.auth.strategy('default', 'jwt', { key: getKey, validateFunc: validateFunc }); + server.route([ + { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } }, + { method: 'POST', path: '/normalError', handler: tokenHandler, config: { auth: 'normalError' } }, + { method: 'POST', path: '/boomError', handler: tokenHandler, config: { auth: 'boomError' } } + ]); }); ['jane', 'john'].forEach(function(user){ - it('uses key function passing ' + user + '\'s token if ' + user + ' is user', function (done) { + it('uses key function passing ' + user + '\'s token if ' + user + ' is user', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader(user) } }; - server.inject(request, function (res) { - expect(res.result).to.exist; - expect(res.result).to.equal(user); + var res = await server.inject(request); + expect(res.result).to.exist; + expect(res.result).to.equal(user); - jwt.verify(getKey.lastToken, keys[user], function(err, decoded){ - if (err) { return done(err); } - expect(decoded.username).to.equal(user); + const decoded = await jwt.verify(getKey.lastToken, keys[user]); + expect(decoded.username).to.equal(user); - done(); - }); - }); }); - it('uses validateFunc function passing ' + user + '\'s extra info if ' + user + ' is user', function (done) { + it('uses validateFunc function passing ' + user + '\'s extra info if ' + user + ' is user', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader(user) } }; - server.inject(request, function (res) { - expect(res.result).to.exist; - expect(res.result).to.equal(user); + const res = await server.inject(request); - expect(validateFunc.lastExtraInfo).to.equal(info[user]); - done(); - }); + expect(res.result).to.exist; + expect(res.result).to.equal(user); + + expect(validateFunc.lastExtraInfo).to.equal(info[user]); }); }); - it('return 500 if an is error thrown when getting key', function(done){ + it('return 500 if an is error thrown when getting key', async function(){ var request = { method: 'POST', url: '/normalError', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - expect(res).to.exist; - expect(res.result.statusCode).to.equal(500); - expect(res.result.error).to.equal('Internal Server Error'); - expect(res.result.message).to.equal('An internal server error occurred'); - done(); - }); + var res = await server.inject(request); + expect(res).to.exist; + expect(res.result.statusCode).to.equal(500); + expect(res.result.error).to.equal('Internal Server Error'); + expect(res.result.message).to.equal('An internal server error occurred'); }); - it('return 403 if an is error thrown when getting key', function(done){ + it('return 403 if an is error thrown when getting key', async function(){ var request = { method: 'POST', url: '/boomError', headers: { authorization: tokenHeader('john') } }; - - server.inject(request, function (res) { - expect(res).to.exist; - expect(res.result.statusCode).to.equal(403); - expect(res.result.error).to.equal('Forbidden'); - expect(res.result.message).to.equal('forbidden'); - done(); - }); + var res = await server.inject(request); + expect(res).to.exist; + expect(res.result.statusCode).to.equal(403); + expect(res.result.error).to.equal('Forbidden'); + expect(res.result.message).to.equal('forbidden'); }); -}); \ No newline at end of file +}); diff --git a/test/index.js b/test/index.js index 64444ca..543874d 100755 --- a/test/index.js +++ b/test/index.js @@ -26,599 +26,514 @@ describe('Token', function () { return 'Bearer ' + Jwt.sign({username : username}, privateKey, options); }; - var loadUser = function (decodedToken, _, callback) { + var loadUser = function (decodedToken) { var username = decodedToken.username; if (username === 'john') { - return callback(null, true, { - user: 'john', - scope: ['a'] - }); + return { + isValid: true, + credentials: {user: 'john', scope: ['a'] } + }; } else if (username === 'jane') { - return callback(Boom.badImplementation()); + throw Boom.badImplementation(); } else if (username === 'invalid1') { - return callback(null, true, 'bad'); + return { + isValid: true, + credentials: 'bad' + }; } else if (username === 'nullman') { - return callback(null, true, null); + return { + isValid: true, + credentials: null, + }; } - - return callback(null, false); - }; - - var tokenHandler = function (request, reply) { - - reply('ok'); + return { + isValid: false, + }; }; - var doubleHandler = function (request, reply) { + var tokenHandler = () => 'ok'; + var doubleHandler = async function (request, h) { var options = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') }, credentials: request.auth.credentials }; + var res = await server.inject(options); - server.inject(options, function (res) { - - reply(res.result); - }); + return res.result; }; var server = new Hapi.Server({ debug: false }); - server.connection(); - before(function (done) { + before(async function () { - server.register(require('../'), function (err) { + await server.register(require('../')) + server.auth.strategy('default', 'jwt', { key: privateKey, validateFunc: loadUser }); + server.auth.default('default'); - expect(err).to.not.exist; - server.auth.strategy('default', 'jwt', 'required', { key: privateKey, validateFunc: loadUser}); + server.route([ + { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } }, + { method: 'POST', path: '/tokenOptional', handler: tokenHandler, config: { auth: { mode: 'optional' } } }, + { method: 'POST', path: '/tokenScope', handler: tokenHandler, config: { auth: { scope: 'x' } } }, + { method: 'POST', path: '/tokenArrayScope', handler: tokenHandler, config: { auth: { scope: ['x', 'y'] } } }, + { method: 'POST', path: '/tokenArrayScopeA', handler: tokenHandler, config: { auth: { scope: ['x', 'y', 'a'] } } }, + { method: 'POST', path: '/double', handler: doubleHandler } + ]); - server.route([ - { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } }, - { method: 'POST', path: '/tokenOptional', handler: tokenHandler, config: { auth: { mode: 'optional' } } }, - { method: 'POST', path: '/tokenScope', handler: tokenHandler, config: { auth: { scope: 'x' } } }, - { method: 'POST', path: '/tokenArrayScope', handler: tokenHandler, config: { auth: { scope: ['x', 'y'] } } }, - { method: 'POST', path: '/tokenArrayScopeA', handler: tokenHandler, config: { auth: { scope: ['x', 'y', 'a'] } } }, - { method: 'POST', path: '/double', handler: doubleHandler } - ]); - - done(); - }); + await server.start(); }); - it('returns a reply on successful auth', function (done) { - + it('returns a reply on successful auth', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - - expect(res.result).to.exist; - expect(res.result).to.equal('ok'); - done(); - }); + var res = await server.inject(request); + expect(res.result).to.exist; + expect(res.result).to.equal('ok'); }); - it('returns decoded token when no validation function is set', function (done) { + it('returns decoded token when no validation function is set', async function () { - var handler = function (request, reply) { + var handler = function (request) { expect(request.auth.isAuthenticated).to.equal(true); expect(request.auth.credentials).to.exist; - reply('ok'); + return 'ok'; }; var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; - - server.auth.strategy('default', 'jwt', 'required', { key: privateKey }); + await server.register(require('../')); - server.route([ - { method: 'POST', path: '/token', handler: handler, config: { auth: 'default' } } - ]); - }); + server.auth.strategy('default', 'jwt', { key: privateKey }); + server.route([ + { method: 'POST', path: '/token', handler: handler, config: { auth: 'default' } } + ]); var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - - expect(res.result).to.exist; - expect(res.result).to.equal('ok'); - done(); - }); + const res = await server.inject(request); + expect(res.result).to.exist; + expect(res.result).to.equal('ok'); }); - it('returns an error on wrong scheme', function (done) { + it('returns an error on wrong scheme', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: 'Steve something' } }; + const res = await server.inject(request) - server.inject(request, function (res) { - - expect(res.statusCode).to.equal(401); - done(); - }); + expect(res.statusCode).to.equal(401); }); - it('returns a reply on successful double auth', function (done) { + it('returns a reply on successful double auth', async function () { var request = { method: 'POST', url: '/double', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { + const res = await server.inject(request); + expect(res.result).to.exist; + expect(res.result).to.equal('ok'); - expect(res.result).to.exist; - expect(res.result).to.equal('ok'); - done(); - }); }); - it('returns a reply on failed optional auth', function (done) { + it('returns a reply on failed optional auth', async function () { var request = { method: 'POST', url: '/tokenOptional' }; - server.inject(request, function (res) { - - expect(res.result).to.equal('ok'); - done(); - }); + const res = await server.inject(request); + expect(res.result).to.equal('ok'); }); - it('returns an error with expired token', function (done) { + it('returns an error with expired token', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', { expiresIn: -10 }) } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt expired'); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await server.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt expired'); + expect(res.statusCode).to.equal(401); + }); - it('returns an error with invalid token', function (done) { + it('returns an error with invalid token', async function () { var token = tokenHeader('john') + '123456123123'; var request = { method: 'POST', url: '/token', headers: { authorization: token } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'invalid signature'); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await server.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'invalid signature'); + expect(res.statusCode).to.equal(401); }); - it('returns an error on bad header format', function (done) { + it('returns an error on bad header format', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: 'Bearer' } }; - server.inject(request, function (res) { + const res = await server.inject(request); + + expect(res.result).to.exist; + expect(res.statusCode).to.equal(400); + expect(res.result.isMissing).to.equal(undefined); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(400); - expect(res.result.isMissing).to.equal(undefined); - done(); - }); }); - it('returns an error on bad header format', function (done) { + it('returns an error on bad header format', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: 'bearer' } }; - server.inject(request, function (res) { + const res = await server.inject(request); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(400); - expect(res.result.isMissing).to.equal(undefined); - done(); - }); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(400); + expect(res.result.isMissing).to.equal(undefined); }); - it('returns an error on bad header internal syntax', function (done) { + it('returns an error on bad header internal syntax', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: 'bearer 123' } }; - server.inject(request, function (res) { + const res = await server.inject(request); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(400); - expect(res.result.isMissing).to.equal(undefined); - done(); - }); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(400); + expect(res.result.isMissing).to.equal(undefined); }); - it('returns an error on unknown user', function (done) { + it('returns an error on unknown user', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('doe') } }; - server.inject(request, function (res) { + const res = await server.inject(request); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(401); - done(); - }); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(401); }); - it('returns an error on internal user lookup error', function (done) { + it('returns an error on internal user lookup error', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('jane') } }; - server.inject(request, function (res) { + const res = await server.inject(request); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(500); - done(); - }); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(500); }); - it('returns an error on non-object credentials error', function (done) { + it('returns an error on non-object credentials error', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('invalid1') } }; - server.inject(request, function (res) { + const res = await server.inject(request); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(500); - done(); - }); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(500); }); - it('returns an error on null credentials error', function (done) { + it('returns an error on null credentials error', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('nullman') } }; - server.inject(request, function (res) { + const res = await server.inject(request); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(500); - done(); - }); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(500); }); - it('returns an error on insufficient scope', function (done) { + it('returns an error on insufficient scope', async function () { var request = { method: 'POST', url: '/tokenScope', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { + const res = await server.inject(request); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(403); - done(); - }); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(403); }); - it('returns an error on insufficient scope specified as an array', function (done) { + it('returns an error on insufficient scope specified as an array', async function () { var request = { method: 'POST', url: '/tokenArrayScope', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { + const res = await server.inject(request); + + expect(res.result).to.exist; + expect(res.statusCode).to.equal(403); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(403); - done(); - }); }); - it('authenticates scope specified as an array', function (done) { + it('authenticates scope specified as an array', async function () { var request = { method: 'POST', url: '/tokenArrayScopeA', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { + const res = await server.inject(request); - expect(res.result).to.exist; - expect(res.statusCode).to.equal(200); - done(); - }); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(200); }); - it('cannot add a route that has payload validation required', function (done) { + it('cannot add a route that has payload validation required', async function () { var fn = function () { - server.route({ method: 'POST', path: '/tokenPayload', handler: tokenHandler, config: { auth: { mode: 'required', payload: 'required' } } }); }; expect(fn).to.throw(Error); - done(); }); - describe('when a single audience is specified for validation', function(){ - var audience = 'https://expected.audience.com'; + describe('when a single audience is specified for validation', async function(){ + var audience = 'https://expected.audience.com'; + var newServer = new Hapi.Server({ debug: false }); - var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; + before(async function () { - server.auth.strategy('default', 'jwt', 'required', { key: privateKey, validateFunc: loadUser, audience: audience}); + await newServer .register(require('../')) + newServer.auth.strategy('default', 'jwt', { key: privateKey, validateFunc: loadUser, audience: audience}); + newServer.auth.default('default'); - server.route([ + newServer .route([ { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } } ]); + + await newServer .start(); }); - - it('fails if token audience is empty', function (done) { + + it('fails if token audience is empty', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt audience invalid. expected: ' + audience); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt audience invalid. expected: ' + audience); + expect(res.statusCode).to.equal(401); }); - it('fails if token audience is invalid', function (done) { - + it('fails if token audience is invalid', async function () { + var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {audience:'https://invalid.audience.com'}) } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt audience invalid. expected: ' + audience); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt audience invalid. expected: ' + audience); + expect(res.statusCode).to.equal(401); }); - it('works if token audience is valid', function (done) { - + it('works if token audience is valid', async function () { + var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {audience: audience}) } }; - server.inject(request, function (res) { - expect(res.result).to.exist; - expect(res.statusCode).to.equal(200); - done(); - }); + const res = await newServer.inject(request); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(200); }); - }); describe('when an array of audiences is specified for validation', function(){ - var audience = 'https://expected.audience.com'; + var audience = 'https://expected.audience.com'; - var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; + var newServer = new Hapi.Server({ debug: false }); - server.auth.strategy('default', 'jwt', 'required', { key: privateKey, validateFunc: loadUser, audience: [audience, 'audience2', 'audience3']}); + before(async function () { + await newServer.register(require('../')) + newServer.auth.strategy('default', 'jwt', { key: privateKey, validateFunc: loadUser, audience: [audience, 'audience2', 'audience3']}); + newServer.auth.default('default'); - server.route([ + newServer.route([ { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } } ]); + + await newServer.start(); }); - - it('fails if token audience is empty', function (done) { + + it('fails if token audience is empty', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt audience invalid. expected: ' + audience + ' or audience2 or audience3'); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt audience invalid. expected: ' + audience + ' or audience2 or audience3'); + expect(res.statusCode).to.equal(401); }); - it('fails if token audience is invalid', function (done) { - + it('fails if token audience is invalid', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {audience:'https://invalid.audience.com'}) } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt audience invalid. expected: ' + audience + ' or audience2 or audience3'); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt audience invalid. expected: ' + audience + ' or audience2 or audience3'); + expect(res.statusCode).to.equal(401); }); - it('works if token audience is one of the expected values', function (done) { - + it('works if token audience is one of the expected values', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {audience: audience}) } }; - server.inject(request, function (res) { - expect(res.result).to.exist; - expect(res.statusCode).to.equal(200); - done(); - }); + const res = await newServer.inject(request); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(200); }); }); describe('when a single issuer is specified for validation', function(){ - var issuer = 'http://expected.issuer'; - - var server = new Hapi.Server({ debug: false}); - server.log(['error', 'database', 'read']); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; + var issuer = 'http://expected.issuer'; - server.auth.strategy('default', 'jwt', 'required', { key: privateKey, validateFunc: loadUser, issuer: issuer}); + var newServer = new Hapi.Server({ debug: false }); - server.route([ + before(async function () { + await newServer.register(require('../')) + newServer.auth.strategy('default', 'jwt', { key: privateKey, validateFunc: loadUser, issuer: issuer}); + newServer.auth.default('default'); + + newServer.route([ { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } } ]); + + await newServer.start(); }); - - it('fails if token issuer is empty', function (done) { - + + it('fails if token issuer is empty', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt issuer invalid. expected: ' + issuer); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt issuer invalid. expected: ' + issuer); + expect(res.statusCode).to.equal(401); }); - it('fails if token issuer is invalid', function (done) { - + it('fails if token issuer is invalid', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {issuer:'https://invalid.issuer'}) } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt issuer invalid. expected: ' + issuer); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt issuer invalid. expected: ' + issuer); + expect(res.statusCode).to.equal(401); }); - it('works if token issuer is valid', function (done) { - + it('works if token issuer is valid', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {issuer: issuer}) } }; - server.inject(request, function (res) { - expect(res.result).to.exist; - expect(res.statusCode).to.equal(200); - done(); - }); + const res = await newServer.inject(request); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(200); }); }); describe('when an array of issuers are specified for validation', function(){ - var issuer = 'http://expected.issuer'; - - var server = new Hapi.Server({ debug: false}); - server.log(['error', 'database', 'read']); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; + var issuer = 'http://expected.issuer'; - server.auth.strategy('default', 'jwt', 'required', { key: privateKey, validateFunc: loadUser, issuer: [issuer,'issuer2','issuer3']}); + var newServer = new Hapi.Server({ debug: false }); + newServer.log(['error', 'database', 'read']); - server.route([ + before(async function () { + await newServer.register(require('../')) + newServer.auth.strategy('default', 'jwt', { key: privateKey, validateFunc: loadUser, issuer: [issuer,'issuer2','issuer3']}); + newServer.auth.default('default'); + + newServer.route([ { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } } ]); + + await newServer.start(); }); - - it('fails if token issuer is empty', function (done) { - + + it('fails if token issuer is empty', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt issuer invalid. expected: ' + issuer + ',issuer2,issuer3'); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt issuer invalid. expected: ' + issuer + ',issuer2,issuer3'); + expect(res.statusCode).to.equal(401); }); - it('fails if token issuer is invalid', function (done) { - + it('fails if token issuer is invalid', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {issuer:'https://invalid.issuer'}) } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt issuer invalid. expected: ' + issuer + ',issuer2,issuer3'); - expect(res.statusCode).to.equal(401); - done(); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt issuer invalid. expected: ' + issuer + ',issuer2,issuer3'); + expect(res.statusCode).to.equal(401); }); - }); - it('works if token issuer contains one of the expected issuers valid', function (done) { - + it('works if token issuer contains one of the expected issuers valid', async function () { + var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {issuer: issuer}) } }; - server.inject(request, function (res) { - expect(res.result).to.exist; - expect(res.statusCode).to.equal(200); - done(); - }); + const res = await newServer.inject(request); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(200); }); }); describe('when RS256 is specified as algorithm for validation', function(){ - var issuer = 'http://expected.issuer'; - - var server = new Hapi.Server({ debug: false}); - server.log(['error', 'database', 'read']); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; + var newServer = new Hapi.Server({ debug: false }); - server.auth.strategy('default', 'jwt', 'required', { key: privateKey, validateFunc: loadUser, algorithms: ['RS256']}); + before(async function () { + await newServer.register(require('../')) + newServer.auth.strategy('default', 'jwt', { key: privateKey, validateFunc: loadUser, algorithms: ['RS256'] }); + newServer.auth.default('default'); - server.route([ + newServer.route([ { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } } ]); + + await newServer.start(); }); - - it('fails if token is signed with HS256 algorithm', function (done) { - + + it('fails if token is signed with HS256 algorithm', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'invalid algorithm'); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'invalid algorithm'); + expect(res.statusCode).to.equal(401); }); }); describe('when HS256 is specified as algorithm for validation', function(){ - var issuer = 'http://expected.issuer'; - - var server = new Hapi.Server({ debug: false}); - server.log(['error', 'database', 'read']); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; + var newServer = new Hapi.Server({ debug: false }); - server.auth.strategy('default', 'jwt', 'required', { key: privateKey, validateFunc: loadUser, algorithms: ['HS256']}); + before(async function () { + await newServer.register(require('../')) + newServer.auth.strategy('default', 'jwt', { key: privateKey, validateFunc: loadUser, algorithms: ['HS256'] }); + newServer.auth.default('default'); - server.route([ + newServer.route([ { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } } ]); + + await newServer.start(); }); - - it('works if token is signed with HS256 algorithm', function (done) { - + + it('works if token is signed with HS256 algorithm', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - expect(res.result).to.exist; - expect(res.statusCode).to.equal(200); - done(); - }); + const res = await newServer.inject(request); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(200); }); }); describe('when subject is specified for validation', function(){ - var subject = 'http://expected.subject'; - - var server = new Hapi.Server({ debug: false}); - server.log(['error', 'database', 'read']); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; + var subject = 'http://expected.subject'; - server.auth.strategy('default', 'jwt', 'required', { key: privateKey, validateFunc: loadUser, subject: subject}); + var newServer = new Hapi.Server({ debug: false }); - server.route([ + before(async function () { + await newServer.register(require('../')) + newServer.auth.strategy('default', 'jwt', { key: privateKey, validateFunc: loadUser, subject: subject }); + newServer.auth.default('default'); + + newServer.route([ { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } } ]); + + await newServer.start(); }); - - it('fails if token subject is empty', function (done) { - + + it('fails if token subject is empty', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john') } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt subject invalid. expected: ' + subject); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt subject invalid. expected: ' + subject); + expect(res.statusCode).to.equal(401); }); - it('fails if token subject is invalid', function (done) { - + it('fails if token subject is invalid', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {subject:'https://invalid.subject'}) } }; - server.inject(request, function (res) { - expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt subject invalid. expected: ' + subject); - expect(res.statusCode).to.equal(401); - done(); - }); + const res = await newServer.inject(request); + expect(res.result.message).to.equal(jwtErrorPrefix + 'jwt subject invalid. expected: ' + subject); + expect(res.statusCode).to.equal(401); }); - it('works if token subject is valid', function (done) { - + it('works if token subject is valid', async function () { var request = { method: 'POST', url: '/token', headers: { authorization: tokenHeader('john', {subject: subject}) } }; - server.inject(request, function (res) { - expect(res.result).to.exist; - expect(res.statusCode).to.equal(200); - done(); - }); + const res = await newServer.inject(request); + expect(res.result).to.exist; + expect(res.statusCode).to.equal(200); }); }); @@ -626,139 +541,100 @@ describe('Token', function () { }); describe('Strategy', function(){ - - it('should fail if strategy is initialized without options', function (done) { - var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; - try { - server.auth.strategy('default', 'jwt', 'required'); - done('Should have failed') - } - catch(err){ - expect(err).to.exist; - expect(err.message).to.equal('"jwt auth strategy options" must be an object'); - done(); - } - }); - }); - it('should fail if strategy is initialized with a string as options', function (done) { - var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; - try { - server.auth.strategy('default', 'jwt', 'required', 'wrong options type'); - done('Should have failed') - } - catch(err){ - expect(err).to.exist; - expect(err.message).to.equal('"jwt auth strategy options" must be an object'); - done(); - } - }); + it('should fail if strategy is initialized without options', async function () { + var server = new Hapi.Server({ debug: false }); + await server.register(require('../')) + try { + server.auth.strategy('default', 'jwt', null); + } + catch(err){ + expect(err).to.exist; + expect(err.message).to.equal('"jwt auth strategy options" must be an object'); + } }); - it('should fail if strategy is initialized with an array as options', function (done) { - var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; - try { - server.auth.strategy('default', 'jwt', 'required', ['wrong', 'options', 'type']); - done('Should have failed') - } - catch(err){ - expect(err).to.exist; - expect(err.message).to.equal('"jwt auth strategy options" must be an object'); - done(); - } - }); + it('should fail if strategy is initialized with a string as options', async function () { + var server = new Hapi.Server({ debug: false }); + await server.register(require('../')) + try { + server.auth.strategy('default', 'jwt', 'wrong options type'); + } + catch(err){ + expect(err).to.exist; + expect(err.message).to.equal('options must be an object'); + } }); - it('should fail if strategy is initialized with a function as options', function (done) { - var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; - try { - server.auth.strategy('default', 'jwt', 'required', function options(){}); - done('Should have failed') - } - catch(err){ - expect(err).to.exist; - expect(err.message).to.equal('"jwt auth strategy options" must be an object'); - done(); - } - }); + + it('should fail if strategy is initialized with an array as options', async function () { + var server = new Hapi.Server({ debug: false }); + await server.register(require('../')) + try { + server.auth.strategy('default', 'jwt', ['wrong', 'options', 'type']); + } + catch(err){ + expect(err).to.exist; + expect(err.message).to.equal('"jwt auth strategy options" must be an object'); + } }); - it('should fail if strategy is initialized without a key in options', function (done) { - var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; - try { - server.auth.strategy('default', 'jwt', 'required', {}); - done(new Error('Should have failed without key in the options')) - } - catch(err){ - expect(err).to.exist; - expect(err.message).to.equal('child "key" fails because ["key" is required]'); - done(); - } - }); + it('should fail if strategy is initialized with a function as options', async function () { + var server = new Hapi.Server({ debug: false }); + + await server.register(require('../')) + try { + server.auth.strategy('default', 'jwt', function options(){}); + } + catch(err){ + expect(err).to.exist; + expect(err.message).to.equal('options must be an object'); + } }); - it('should fail if strategy is initialized with an invalid key type in options', function (done) { - var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; - try { - server.auth.strategy('default', 'jwt', 'required', {key:10}); - done(new Error('Should have failed with an invalid key type in options')) - } - catch(err){ - expect(err).to.exist; - expect(err.message).to.equal('child "key" fails because ["key" must be a buffer or a string, "key" must be a Function]'); - done(); - } - }); + it('should fail if strategy is initialized without a key in options', async function () { + var server = new Hapi.Server({ debug: false }); + await server.register(require('../')); + try { + server.auth.strategy('default', 'jwt', {}); + } + catch(err){ + expect(err).to.exist; + expect(err.message).to.equal('child "key" fails because ["key" is required]'); + } }); - it('should work if strategy is initialized with a Bugger as key in options', function (done) { + + it('should fail if strategy is initialized with an invalid key type in options', async function () { var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; - try { - server.auth.strategy('default', 'jwt', 'required', {key: new Buffer('mySuperSecret', 'base64')}); - done(); - } - catch(err){ - done(err); - } - }); + await server.register(require('../')); + try { + server.auth.strategy('default', 'jwt', {key:10}); + } + catch(err){ + expect(err.message).to.equal('child "key" fails because ["key" must be a buffer or a string, "key" must be a Function]'); + } }); - it('should fail if strategy is initialized with an invalid audience type in options', function (done) { + it('should work if strategy is initialized with a Bugger as key in options', async function () { var server = new Hapi.Server({ debug: false }); - server.connection(); - server.register(require('../'), function (err) { - expect(err).to.not.exist; - try { - server.auth.strategy('default', 'jwt', 'required', {key: '123456', audience: 123}); - done(new Error('Should have failed with an invalid audience type in options')) - } - catch(err){ - expect(err).to.exist; - expect(err.message).to.equal('child "audience" fails because ["audience" must be a string, "audience" must be an array]'); - done(); - } - }); + await server.register(require('../')); + try { + server.auth.strategy('default', 'jwt', {key: new Buffer('mySuperSecret', 'base64')}); + } catch (e) { + Code.fail('This should not occur'); + } }); -}); \ No newline at end of file + it('should fail if strategy is initialized with an invalid audience type in options', async function () { + var server = new Hapi.Server({ debug: false }); + await server.register(require('../')); + try { + server.auth.strategy('default', 'jwt', {key: '123456', audience: 123}); + } + catch(err){ + expect(err).to.exist; + expect(err.message).to.equal('child "audience" fails because ["audience" must be a string, "audience" must be an array]'); + } + }); +}); From e8a94b7615375204fe2a1a98c64342af6e363ad9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Diaz?= Date: Mon, 5 Feb 2018 17:04:47 -0300 Subject: [PATCH 3/7] Update README.md --- README.md | 61 +++++++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 6d838af..d1e2935 100755 --- a/README.md +++ b/README.md @@ -26,9 +26,7 @@ See the example folder for an executable example. var Hapi = require('hapi'), jwt = require('jsonwebtoken'), - server = new Hapi.Server(); - -server.connection({ port: 8080 }); + server = new Hapi.Server({ port: 8080 }); var accounts = { @@ -49,49 +47,50 @@ var privateKey = 'BbZJjyoXAdr8BUZuiKKARWimKfrSmQ6fv8kZ7OFfc'; var token = jwt.sign({ accountId: 123 }, privateKey); -var validate = function (decodedToken, extraInfo, callback) { +var validate = async function (decodedToken, extraInfo) { - var error, - credentials = accounts[decodedToken.accountId] || {}; + var credentials = accounts[decodedToken.accountId] || {}; if (!credentials) { - return callback(error, false, credentials); + return { isValid: false }; } - return callback(error, true, credentials) + return { + isValid: true, + credentials:credentials + } }; -server.register(require('hapi-auth-jwt'), function (error) { +await server.register(require('hapi-auth-jwt')); - server.auth.strategy('token', 'jwt', { - key: privateKey, - validateFunc: validate - }); +server.auth.strategy('token', 'jwt', { + key: privateKey, + validateFunc: validate +}); - server.route({ - method: 'GET', - path: '/', - config: { - auth: 'token' - } - }); +server.route({ + method: 'GET', + path: '/', + config: { + auth: 'token' + } +}); // With scope requirements - server.route({ - method: 'GET', - path: '/withScope', - config: { - auth: { - strategy: 'token', - scope: ['a'] - } +server.route({ + method: 'GET', + path: '/withScope', + config: { + auth: { + strategy: 'token', + scope: ['a'] } - }); + } }); -server.start(); +await server.start(); ``` @@ -106,4 +105,4 @@ server.auth.strategy('token', 'jwt', { algorithms: ['RS256'], subject: 'myRequiredSubject' }); -``` \ No newline at end of file +``` From 64dcf12b4a142495bbf4be644473440db92b6362 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Luis=20Diaz?= Date: Mon, 5 Feb 2018 17:05:17 -0300 Subject: [PATCH 4/7] Version BUMP --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bcf3d58..c38c07e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hapi-auth-jwt", "description": "JSON Web Token (JWT) authentication plugin", - "version": "4.1.0", + "version": "5.0.0", "author": "Ryan Fitzgerald ", "repository": "git://github.com/ryanfitz/hapi-auth-jwt", "main": "index", From 19573081ee73ba5bc9797c27bbf8fa3ea25e5f77 Mon Sep 17 00:00:00 2001 From: Damian Fortuna Date: Wed, 14 Feb 2018 10:44:09 -0300 Subject: [PATCH 5/7] Apply some feedback --- README.md | 24 ++++++++++++------------ lib/index.js | 16 +++------------- package.json | 2 +- test/index.js | 32 ++++++++++++++++---------------- 4 files changed, 32 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index d1e2935..ee534fc 100755 --- a/README.md +++ b/README.md @@ -24,12 +24,12 @@ See the example folder for an executable example. ```javascript -var Hapi = require('hapi'), - jwt = require('jsonwebtoken'), - server = new Hapi.Server({ port: 8080 }); +const Hapi = require('hapi'); +const jwt = require('jsonwebtoken'); +const server = new Hapi.Server({ port: 8080 }); -var accounts = { +const accounts = { 123: { id: 123, user: 'john', @@ -39,15 +39,15 @@ var accounts = { }; -var privateKey = 'BbZJjyoXAdr8BUZuiKKARWimKfrSmQ6fv8kZ7OFfc'; +const privateKey = 'BbZJjyoXAdr8BUZuiKKARWimKfrSmQ6fv8kZ7OFfc'; -// Use this token to build your request with the 'Authorization' header. +// Use this token to build your request with the 'Authorization' header. // Ex: // Authorization: Bearer -var token = jwt.sign({ accountId: 123 }, privateKey); +const token = jwt.sign({ accountId: 123 }, privateKey); -var validate = async function (decodedToken, extraInfo) { +const validate = async function (decodedToken, extraInfo) { var credentials = accounts[decodedToken.accountId] || {}; @@ -55,9 +55,9 @@ var validate = async function (decodedToken, extraInfo) { return { isValid: false }; } - return { - isValid: true, - credentials:credentials + return { + isValid: true, + credentials } }; @@ -105,4 +105,4 @@ server.auth.strategy('token', 'jwt', { algorithms: ['RS256'], subject: 'myRequiredSubject' }); -``` +``` diff --git a/lib/index.js b/lib/index.js index 64dd566..13c37ad 100755 --- a/lib/index.js +++ b/lib/index.js @@ -64,12 +64,7 @@ internals.implementation = function (server, options) { settings.key : function (req, token) { return { key: settings.key }; }; - let keyResult; - try { - keyResult = await getKey(request, token); - } catch (err) { - throw err; - } + const keyResult = await getKey(request, token); const { key, extraInfo } = keyResult; let decoded; @@ -83,12 +78,7 @@ internals.implementation = function (server, options) { return h.authenticated({ credentials: decoded }); } - let validateResult; - try { - validateResult = await settings.validateFunc(decoded, extraInfo); - } catch (err) { - throw err; - } + const validateResult = await settings.validateFunc(decoded, extraInfo); const { isValid, credentials } = validateResult; @@ -101,7 +91,7 @@ internals.implementation = function (server, options) { } // Authenticated - return h.authenticated({ credentials: credentials }); + return h.authenticated({ credentials }); } }; diff --git a/package.json b/package.json index c38c07e..9be5e56 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "JWT" ], "engines": { - "node": ">=8.x.x" + "node": ">=8.9.x" }, "dependencies": { "boom": "2.x.x", diff --git a/test/index.js b/test/index.js index 543874d..7f34528 100755 --- a/test/index.js +++ b/test/index.js @@ -278,11 +278,11 @@ describe('Token', function () { before(async function () { - await newServer .register(require('../')) + await newServer.register(require('../')) newServer.auth.strategy('default', 'jwt', { key: privateKey, validateFunc: loadUser, audience: audience}); newServer.auth.default('default'); - newServer .route([ + newServer.route([ { method: 'POST', path: '/token', handler: tokenHandler, config: { auth: 'default' } } ]); @@ -547,8 +547,8 @@ describe('Strategy', function(){ await server.register(require('../')) try { server.auth.strategy('default', 'jwt', null); - } - catch(err){ + expect.fail('should have thrown'); + } catch(err){ expect(err).to.exist; expect(err.message).to.equal('"jwt auth strategy options" must be an object'); } @@ -559,8 +559,8 @@ describe('Strategy', function(){ await server.register(require('../')) try { server.auth.strategy('default', 'jwt', 'wrong options type'); - } - catch(err){ + expect.fail('should have thrown'); + } catch(err){ expect(err).to.exist; expect(err.message).to.equal('options must be an object'); } @@ -572,8 +572,8 @@ describe('Strategy', function(){ await server.register(require('../')) try { server.auth.strategy('default', 'jwt', ['wrong', 'options', 'type']); - } - catch(err){ + expect.fail('should have thrown'); + } catch(err){ expect(err).to.exist; expect(err.message).to.equal('"jwt auth strategy options" must be an object'); } @@ -585,8 +585,8 @@ describe('Strategy', function(){ await server.register(require('../')) try { server.auth.strategy('default', 'jwt', function options(){}); - } - catch(err){ + expect.fail('should have thrown'); + } catch(err){ expect(err).to.exist; expect(err.message).to.equal('options must be an object'); } @@ -597,8 +597,8 @@ describe('Strategy', function(){ await server.register(require('../')); try { server.auth.strategy('default', 'jwt', {}); - } - catch(err){ + expect.fail('should have thrown'); + } catch(err){ expect(err).to.exist; expect(err.message).to.equal('child "key" fails because ["key" is required]'); } @@ -610,8 +610,8 @@ describe('Strategy', function(){ await server.register(require('../')); try { server.auth.strategy('default', 'jwt', {key:10}); - } - catch(err){ + expect.fail('should have thrown'); + } catch(err){ expect(err.message).to.equal('child "key" fails because ["key" must be a buffer or a string, "key" must be a Function]'); } }); @@ -631,8 +631,8 @@ describe('Strategy', function(){ await server.register(require('../')); try { server.auth.strategy('default', 'jwt', {key: '123456', audience: 123}); - } - catch(err){ + expect.fail('should have thrown'); + } catch(err){ expect(err).to.exist; expect(err.message).to.equal('child "audience" fails because ["audience" must be a string, "audience" must be an array]'); } From 7741cef6f0252332dbb87f2b937d638720d9d215 Mon Sep 17 00:00:00 2001 From: Damian Fortuna Date: Wed, 14 Feb 2018 14:10:58 -0300 Subject: [PATCH 6/7] Apply more feedback --- lib/index.js | 17 ++++++++++------- test/dynamicKeys.tests.js | 2 +- test/index.js | 3 +-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/index.js b/lib/index.js index 13c37ad..482cc5a 100755 --- a/lib/index.js +++ b/lib/index.js @@ -21,11 +21,6 @@ function register(server, options) { server.auth.scheme('jwt', internals.implementation); }; -function isFunction(functionToCheck) { - const objectProto = Object.prototype.toString.call(functionToCheck); - return objectProto === '[object Function]' || objectProto === '[object AsyncFunction]'; -} - internals.implementation = function (server, options) { var validationResult = Joi.validate(options, optionsSchema); @@ -60,11 +55,19 @@ internals.implementation = function (server, options) { var token = parts[1]; - var getKey = isFunction(settings.key) ? + var getKey = typeof settings.key === 'function' ? settings.key : function (req, token) { return { key: settings.key }; }; - const keyResult = await getKey(request, token); + + let keyResult; + + try { + keyResult = await getKey(request, token); + } catch (err) { + throw Boom.boomify(err); + } + const { key, extraInfo } = keyResult; let decoded; diff --git a/test/dynamicKeys.tests.js b/test/dynamicKeys.tests.js index 0eb79eb..4c6a641 100644 --- a/test/dynamicKeys.tests.js +++ b/test/dynamicKeys.tests.js @@ -51,7 +51,7 @@ describe('Dynamic Secret', function () { } }; - var validateFunc = function(decoded, extraInfo){ + var validateFunc = async function(decoded, extraInfo){ validateFunc.lastExtraInfo = extraInfo; return { diff --git a/test/index.js b/test/index.js index 7f34528..a5084ef 100755 --- a/test/index.js +++ b/test/index.js @@ -406,7 +406,6 @@ describe('Token', function () { var issuer = 'http://expected.issuer'; var newServer = new Hapi.Server({ debug: false }); - newServer.log(['error', 'database', 'read']); before(async function () { await newServer.register(require('../')) @@ -616,7 +615,7 @@ describe('Strategy', function(){ } }); - it('should work if strategy is initialized with a Bugger as key in options', async function () { + it('should work if strategy is initialized with a Buffer as key in options', async function () { var server = new Hapi.Server({ debug: false }); await server.register(require('../')); try { From c6627afc986d0cfec958d0948a2d2ecf79f47392 Mon Sep 17 00:00:00 2001 From: Damian Fortuna Date: Wed, 14 Feb 2018 18:21:55 -0300 Subject: [PATCH 7/7] Update dependencies --- lib/index.js | 2 +- package.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/index.js b/lib/index.js index 482cc5a..fa7fec0 100755 --- a/lib/index.js +++ b/lib/index.js @@ -65,7 +65,7 @@ internals.implementation = function (server, options) { try { keyResult = await getKey(request, token); } catch (err) { - throw Boom.boomify(err); + throw Boom.boomify(err, { override: false }); } const { key, extraInfo } = keyResult; diff --git a/package.json b/package.json index 9be5e56..d1832f3 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,10 @@ "node": ">=8.9.x" }, "dependencies": { - "boom": "2.x.x", - "hoek": "2.x.x", - "joi": "^10.0.1", - "jsonwebtoken": "^5.4.1" + "boom": "^7.1.1", + "hoek": "^5.0.3", + "joi": "^13.1.2", + "jsonwebtoken": "^8.1.1" }, "devDependencies": { "code": "5.x.x",