diff --git a/.eslintrc b/.eslintrc index 8e6a526..161b68c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -5,3 +5,6 @@ extends: plugin:fxa/server rules: handle-callback-err: 0 semi: [2, "always"] + +parserOptions: + ecmaVersion: 2018 diff --git a/bin/_static.js b/bin/_static.js index b370f2b..4e86fbf 100644 --- a/bin/_static.js +++ b/bin/_static.js @@ -4,13 +4,15 @@ const config = require('../lib/config').getProperties(); const logger = require('../lib/logging')('bin._static'); -const server = require('../lib/server/_static').create(); + +async function create() { + const server = await require('../lib/server/_static').create(); + await server.start(); + logger.info('listening', server.info.uri); +} +create(); if (config.env !== 'development') { logger.warn('sanity-check', 'static bin should only be used for local dev!'); } - -server.start(function() { - logger.info('listening', server.info.uri); -}); diff --git a/bin/server.js b/bin/server.js index 2c63ca2..63c5a54 100644 --- a/bin/server.js +++ b/bin/server.js @@ -9,21 +9,30 @@ require('../lib/newrelic')(); const configuration = require('../lib/config'); const db = require('../lib/db'); const logger = require('../lib/logging')('bin.server'); -const server = require('../lib/server').create(); -const events = require('../lib/events')(server); // The stringify/parse is to force the output back to unindented json. logger.info('config', JSON.stringify(JSON.parse(configuration.toString()))); -db.ping().done(function() { - server.start(function(err) { - if (err) { - logger.critical('server.start', err); - process.exit(1); - } + + +async function start() { + const server = await require('../lib/server').create(); + + try { + await db.ping(); + } catch (err) { + logger.critical('db.ping', err); + process.exit(2); + } + try { + await server.start(); logger.info('listening', server.info.uri); - }); - events.start(); -}, function(err) { - logger.critical('db.ping', err); - process.exit(2); -}); + const events = require('../lib/events')(server); + events.start(); + } catch (err) { + logger.critical('server.start', err); + process.exit(1); + } +} + +start(); + diff --git a/bin/worker.js b/bin/worker.js index 70309b9..06998f1 100644 --- a/bin/worker.js +++ b/bin/worker.js @@ -7,8 +7,13 @@ require('../lib/newrelic')(); const logger = require('../lib/logging')('bin.worker'); -const server = require('../lib/server/worker').create(); -server.start(function() { +async function start() { + const server = await require('../lib/server/worker').create(); + + await server.start(); logger.info('listening', server.info.uri); -}); +} + +start(); + diff --git a/lib/batch.js b/lib/batch.js index 563d240..875008f 100644 --- a/lib/batch.js +++ b/lib/batch.js @@ -7,12 +7,6 @@ const Boom = require('boom'); const logger = require('./logging')('batch'); const P = require('./promise'); -function inject(server, options) { - return new P(function(resolve) { - server.inject(options, resolve); - }); -} - // Make multiple internal requests to routes, and merge their responses // into a single object. // @@ -46,7 +40,7 @@ function batch(request, routeFieldsMap) { let numForbidden = 0; const routeFieldsKeys = Object.keys(routeFieldsMap); return P.each(routeFieldsKeys, url => { - return inject(request.server, { + return request.server.inject({ allowInternals: true, method: 'get', url: url, diff --git a/lib/events.js b/lib/events.js index 0132648..22b53d8 100644 --- a/lib/events.js +++ b/lib/events.js @@ -45,9 +45,10 @@ module.exports = function (server) { function primaryEmailChanged(message) { var userId = getUserId(message); return P.resolve().then(() => { - server.methods.profileCache.drop(userId, () => { - logger.info('primaryEmailChanged:cacheCleared', {uid: userId}); - }); + server.methods.profileCache.drop(userId) + .then(() => { + logger.info('primaryEmailChanged:cacheCleared', {uid: userId}); + }); }).then(function () { logger.info(message.event, {uid: userId}); }); @@ -56,9 +57,10 @@ module.exports = function (server) { function profileDataChanged(message) { var userId = getUserId(message); return P.resolve().then(function () { - server.methods.profileCache.drop(userId, () => { - logger.info('profileDataChanged:cacheCleared', {uid: userId}); - }); + server.methods.profileCache.drop(userId) + .then(() => { + logger.info('profileDataChanged:cacheCleared', {uid: userId}); + }); }).then(function () { logger.info(message.event, {uid: userId}); }); diff --git a/lib/profileCache.js b/lib/profileCache.js index 14a45c9..01cff23 100644 --- a/lib/profileCache.js +++ b/lib/profileCache.js @@ -51,28 +51,27 @@ function getProfileCacheKey(req) { } -module.exports = function profileCache(server, options, next) { +module.exports = function profileCache(server, options) { // Fetch all available profile data given the scopes on the request, // using cached data if possible. - server.method('profileCache.get', (req, next) => { - batch(req, { + server.method('profileCache.get', (req) => { + return batch(req, { '/v1/_core_profile': true, '/v1/uid': true, '/v1/avatar': ['avatar', 'avatarDefault'], '/v1/display_name': true }) - .then(result => { - // Only cache the result if we can produce a suitable cache key. - const ttl = getProfileCacheKey(req) ? undefined : 0; - return next(null, result, ttl); - }) - .catch(next); + .then((result) => { + // Only cache the result if we can produce a suitable cache key. + const ttl = getProfileCacheKey(req) ? undefined : 0; + return { result, ttl }; + }); }, { cache: { expiresIn: options.expiresIn, - generateTimeout: options.generateTimeout + generateTimeout: options.generateTimeout || 100 }, generateKey: (req) => { return getProfileCacheKey(req) || 'can-not-cache'; @@ -81,24 +80,20 @@ module.exports = function profileCache(server, options, next) { // Drop any cached profile data for the given user. - server.method('profileCache.drop', (uid, next) => { + server.method('profileCache.drop', (uid) => { // To work transparently with hapi's caching and `getProfileCacheKey` above, // we make a bunch of synthetic request objects on which to drop the // cache, one for each possible set of scopes in the cache. - return P.each(CACHEABLE_SCOPES, scope => { + return P.each(CACHEABLE_SCOPES, (scope) => { const req = { auth: { credentials: { user: uid, scope: scope }}}; - return P.fromCallback(cb => { - server.methods.profileCache.get.cache.drop(req, cb); + return server.methods.profileCache.get.cache.drop(req); + }) + .catch((err) => { + throw err; }); - }).asCallback(next); }); - - next(); }; -module.exports.attributes = { - name: 'fxa-profile-cache' -}; diff --git a/lib/routes/_core_profile.js b/lib/routes/_core_profile.js index f54a5fb..e0262ca 100644 --- a/lib/routes/_core_profile.js +++ b/lib/routes/_core_profile.js @@ -30,62 +30,66 @@ module.exports = { twoFactorAuthentication: Joi.boolean().optional() } }, - handler: function _core_profile(req, reply) { - request.get(AUTH_SERVER_URL, { - headers: { - Authorization: 'Bearer ' + req.auth.credentials.token - }, - json: true - }, (err, res, body) => { - if (err) { - logger.error('request.auth_server.network', err); - return reply(new AppError.authError('network error')); - } - if (res.statusCode >= 400) { - body = body && body.code ? body : { code: res.statusCode }; - if (res.statusCode >= 500) { - logger.error('request.auth_server.fail', body); - return reply(new AppError.authError('auth-server server error')); - } - // Return Unauthorized if the token turned out to be invalid, - // or if the account has been deleted on the auth-server. - // (we can still have valid oauth tokens for deleted accounts, - // because distributed state). - if (body.code === 401 || body.errno === 102) { - logger.info('request.auth_server.fail', body); - return reply(new AppError.unauthorized(body.message)); - } - // There should be no other 400-level errors, unless we're - // sending a badly-formed request of our own. That warrants - // an "Internal Server Error" on our part. - logger.error('request.auth_server.fail', body); - return reply(new AppError({ - code: 500, - message: 'error communicating with auth server' - })); - } + handler: async function _core_profile(req) { + function makeReq() { + return new Promise((resolve, reject) => { + request.get(AUTH_SERVER_URL, { + headers: { + Authorization: 'Bearer ' + req.auth.credentials.token + }, + json: true + }, (err, res, body) => { + if (err) { + logger.error('request.auth_server.network', err); + return reject(new AppError.authError('network error')); + } + if (res.statusCode >= 400) { + body = body && body.code ? body : { code: res.statusCode }; + if (res.statusCode >= 500) { + logger.error('request.auth_server.fail', body); + return reject(AppError.authError('auth-server server error')); + } + // Return Unauthorized if the token turned out to be invalid, + // or if the account has been deleted on the auth-server. + // (we can still have valid oauth tokens for deleted accounts, + // because distributed state). + if (body.code === 401 || body.errno === 102) { + logger.info('request.auth_server.fail', body); + return reject(new AppError.unauthorized(body.message)); + } + // There should be no other 400-level errors, unless we're + // sending a badly-formed request of our own. That warrants + // an "Internal Server Error" on our part. + logger.error('request.auth_server.fail', body); + return reject(new AppError({ + code: 500, + message: 'error communicating with auth server' + })); + } - if (! body) { - return reply( - new AppError('empty body from auth response') - ); - } - const result = {}; - if (typeof body.email !== 'undefined') { - result.email = body.email; - } - if (typeof body.locale !== 'undefined') { - result.locale = body.locale; - } - // Translate from internal terminology into OAuth-style terminology. - if (typeof body.authenticationMethods !== 'undefined') { - result.amrValues = body.authenticationMethods; - } - if (typeof body.authenticatorAssuranceLevel !== 'undefined') { - result.twoFactorAuthentication = body.authenticatorAssuranceLevel >= 2; - } - reply(result); - }); + if (! body) { + return reject(AppError('empty body from auth response')); + } + const result = {}; + if (typeof body.email !== 'undefined') { + result.email = body.email; + } + if (typeof body.locale !== 'undefined') { + result.locale = body.locale; + } + // Translate from internal terminology into OAuth-style terminology. + if (typeof body.authenticationMethods !== 'undefined') { + result.amrValues = body.authenticationMethods; + } + if (typeof body.authenticatorAssuranceLevel !== 'undefined') { + result.twoFactorAuthentication = body.authenticatorAssuranceLevel >= 2; + } + return resolve(result); + }); + }); + } + + return makeReq().then(result => result); } }; diff --git a/lib/routes/avatar/delete.js b/lib/routes/avatar/delete.js index 4d28f8a..9a468ee 100644 --- a/lib/routes/avatar/delete.js +++ b/lib/routes/avatar/delete.js @@ -31,41 +31,41 @@ module.exports = { .optional() } }, - handler: function deleteAvatar(req, reply) { + handler: async function deleteAvatar(req) { if (req.params.id === DEFAULT_AVATAR_ID) { // if we are clearing the default avatar then do nothing - return reply({}); + return {}; } const uid = req.auth.credentials.user; let avatar, lookup; - req.server.methods.profileCache.drop(uid, () => { - if (req.params.id) { - lookup = getAvatar(req.params.id, uid); - } else { - lookup = getSelectedAvatar(uid); - } - - return lookup.then(av => { - avatar = av; - return P.all([ - db.deleteAvatar(avatar.id), - db.getProviderById(avatar.providerId) - ]); - }) - .spread((_, provider) => { - logger.debug('provider', provider); - if (provider.name === FXA_PROVIDER) { - return workers.delete(avatar.id); - } - }) + return req.server.methods.profileCache.drop(uid) .then(() => { - notifyProfileUpdated(uid); // Don't wait on promise - return EMPTY; - }) - .done(reply, reply); - }); + if (req.params.id) { + lookup = getAvatar(req.params.id, uid); + } else { + lookup = getSelectedAvatar(uid); + } + + return lookup.then(av => { + avatar = av; + return P.all([ + db.deleteAvatar(avatar.id), + db.getProviderById(avatar.providerId) + ]); + }) + .spread((_, provider) => { + logger.debug('provider', provider); + if (provider.name === FXA_PROVIDER) { + return workers.delete(avatar.id); + } + }) + .then(() => { + notifyProfileUpdated(uid); // Don't wait on promise + return EMPTY; + }); + }); } }; diff --git a/lib/routes/avatar/get.js b/lib/routes/avatar/get.js index a527335..d199c8b 100644 --- a/lib/routes/avatar/get.js +++ b/lib/routes/avatar/get.js @@ -42,22 +42,22 @@ module.exports = { avatar: Joi.string().max(256) } }, - handler: function avatar(req, reply) { + handler: async function avatar(req, h) { var uid = req.auth.credentials.user; - db.getSelectedAvatar(uid) + return db.getSelectedAvatar(uid) .then(avatarOrDefault) - .done(function (result) { - var rep = reply(result); + .then(function (result) { + var rep = result; if (result.id) { var info = { event: 'avatar.get', uid: uid }; logger.info('activityEvent', info); - rep = rep.etag(result.id); + rep = h.response(result).etag(result.id); } return rep; - }, reply); + }); } }; diff --git a/lib/routes/avatar/upload.js b/lib/routes/avatar/upload.js index 1ae9c69..4f75391 100644 --- a/lib/routes/avatar/upload.js +++ b/lib/routes/avatar/upload.js @@ -46,23 +46,17 @@ module.exports = { url: Joi.string().required() } }, - handler: function upload(req, reply) { + handler: async function upload(req, h) { const uid = req.auth.credentials.user; - req.server.methods.profileCache.drop(uid, () => { - const id = img.id(); - // precaution to avoid the default id from being overwritten - assert(id !== DEFAULT_AVATAR_ID); - const url = avatarShared.fxaUrl(id); - workers.upload(id, req.payload, req.headers) - .then(function save() { - return db.addAvatar(id, uid, url, FXA_PROVIDER); - }) - .done(function uploadDone() { - notifyProfileUpdated(uid); // Don't wait on promise - reply({ url: url, id: hex(id) }).code(201); - }, reply); - }); - + await req.server.methods.profileCache.drop(uid); + const id = img.id(); + // precaution to avoid the default id from being overwritten + assert(id !== DEFAULT_AVATAR_ID); + const url = avatarShared.fxaUrl(id); + await workers.upload(id, req.payload, req.headers); + await db.addAvatar(id, uid, url, FXA_PROVIDER); + notifyProfileUpdated(uid); // Don't wait on promise + return h.response({ url: url, id: hex(id) }).code(201); } }; diff --git a/lib/routes/display_name/get.js b/lib/routes/display_name/get.js index 4f954d7..21a8e2d 100644 --- a/lib/routes/display_name/get.js +++ b/lib/routes/display_name/get.js @@ -17,16 +17,16 @@ module.exports = { displayName: Joi.string().max(256) } }, - handler: function avatar(req, reply) { - db.getDisplayName(req.auth.credentials.user) - .done(function (result) { + handler: async function avatar(req, h) { + return db.getDisplayName(req.auth.credentials.user) + .then(function (result) { if (result && result.displayName) { - reply({ displayName: result.displayName }) + return h.response({ displayName: result.displayName }) .etag(checksum(result.displayName)); } else { - reply({}).code(204); + return h.response({}).code(204); } - }, reply); + }); } }; diff --git a/lib/routes/display_name/post.js b/lib/routes/display_name/post.js index ca5d772..df0ecf1 100644 --- a/lib/routes/display_name/post.js +++ b/lib/routes/display_name/post.js @@ -32,18 +32,13 @@ module.exports = { displayName: Joi.string().max(256).required().allow('').regex(ALLOWED_DISPLAY_NAME_CHARS) } }, - handler: function avatarPost(req, reply) { + handler: async function avatarPost(req) { const uid = req.auth.credentials.user; - req.server.methods.profileCache.drop(uid, () => { - const payload = req.payload; - db.setDisplayName(uid, payload.displayName) - .then(() => { - notifyProfileUpdated(uid); // Don't wait on promise - return EMPTY; - }) - .done(reply, reply); - }); - + await req.server.methods.profileCache.drop(uid); + const payload = req.payload; + await db.setDisplayName(uid, payload.displayName); + notifyProfileUpdated(uid); // Don't wait on promise + return EMPTY; } }; diff --git a/lib/routes/email.js b/lib/routes/email.js index 55165a1..ae86d11 100644 --- a/lib/routes/email.js +++ b/lib/routes/email.js @@ -17,29 +17,30 @@ module.exports = { email: Joi.string().required() } }, - handler: function email(req, reply) { - req.server.inject({ + handler: async function email(req) { + return req.server.inject({ allowInternals: true, method: 'get', url: '/v1/_core_profile', headers: req.headers, credentials: req.auth.credentials - }, res => { - if (res.statusCode !== 200) { - return reply(res); - } - // Since this route requires 'email' scope, - // we should always get an email field back. - if (! res.result.email) { - logger.error('request.auth_server.fail', res.result); - return reply(new AppError({ - code: 500, - message: 'auth server did not return email' - })); - } - return reply({ - email: res.result.email + }) + .then(res => { + if (res.statusCode !== 200) { + return res; + } + // Since this route requires 'email' scope, + // we should always get an email field back. + if (! res.result.email) { + logger.error('request.auth_server.fail', res.result); + throw new AppError({ + code: 500, + message: 'auth server did not return email' + }); + } + return { + email: res.result.email + }; }); - }); } }; diff --git a/lib/routes/heartbeat.js b/lib/routes/heartbeat.js index 20dbad8..ccabf4e 100644 --- a/lib/routes/heartbeat.js +++ b/lib/routes/heartbeat.js @@ -5,7 +5,7 @@ const db = require('../db'); module.exports = { - handler: function heartbeat(req, reply) { - db.ping().done(reply, reply); + handler: async function heartbeat() { + return db.ping().then(() => {}); } }; diff --git a/lib/routes/lbheartbeat.js b/lib/routes/lbheartbeat.js index 489ae36..ce47bb8 100644 --- a/lib/routes/lbheartbeat.js +++ b/lib/routes/lbheartbeat.js @@ -3,8 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ module.exports = { - handler: function lbheartbeat(req, reply) { - reply({'http': 'okay'}); + handler: async function lbheartbeat() { + return {'http': 'okay'}; } }; diff --git a/lib/routes/profile.js b/lib/routes/profile.js index deae10e..f38f2d5 100644 --- a/lib/routes/profile.js +++ b/lib/routes/profile.js @@ -4,6 +4,7 @@ const Joi = require('joi'); const checksum = require('checksum'); +const P = require('../promise'); const logger = require('../logging')('routes.profile'); @@ -33,22 +34,25 @@ module.exports = { sub: Joi.string().allow(null) } }, - handler: function profile(req, reply) { + handler: async function profile(req, h) { const server = req.server; const creds = req.auth.credentials; - server.methods.profileCache.get(req, (err, result, cached, report) => { - if (err) { - return reply(err); - } + function createResponse (result, cached, report) { + // `profileChangedAt` is an internal implementation detail that we don't + // return to reliers. As of now, we don't expect them to have any + // use for this. + result = result.result; + delete result.profileChangedAt; + if (creds.scope.indexOf('openid') !== -1) { result.sub = creds.user; } - let rep = reply(result); + let rep = h.response(result); const etag = computeEtag(result); if (etag) { - rep = rep.etag(etag); + rep = h.response(result).etag(etag); } const lastModified = cached ? new Date(cached.stored) : new Date(); if (cached) { @@ -60,8 +64,24 @@ module.exports = { } else { logger.info('batch.db'); } + return rep.header('last-modified', lastModified.toUTCString()); - }); + } + + return server.methods.profileCache.get(req) + .then(async (result, cached, report) => { + // Check to see if the oauth-server is reporting a newer `profileChangedAt` + // timestamp from validating the token, if so, lets invalidate the cache + // and set new value. + if (result.profileChangedAt < creds.profileChangedAt) { + await server.methods.profileCache.drop(creds.user); + logger.info('profileChangedAt:cacheCleared', {uid: creds.user}); + return server.methods.profileCache.get(req) + .then(() => createResponse); + } + + return createResponse(result, cached, report); + }); } }; diff --git a/lib/routes/root.js b/lib/routes/root.js index f6e8db0..adde436 100644 --- a/lib/routes/root.js +++ b/lib/routes/root.js @@ -27,9 +27,9 @@ module.exports = { source: Joi.string().required(), } }, - handler: function index(req, reply) { - function sendReply() { - reply({ + handler: async function index(req, h) { + function getResp() { + return h.response({ version: version, commit: commitHash, source: source @@ -37,20 +37,27 @@ module.exports = { } if (commitHash) { - return sendReply(); + return getResp(); } - // figure it out from .git - const gitDir = path.resolve(__dirname, '..', '..', '.git'); - exec('git rev-parse HEAD', { cwd: gitDir }, (err, stdout) => { // eslint-disable-line handle-callback-err - commitHash = stdout.replace(/\s+/, ''); - const configPath = path.join(gitDir, 'config'); - const cmd = 'git config --get remote.origin.url'; - const env = Object.assign({}, process.env, { GIT_CONFIG: configPath }); - exec(cmd, { env }, (err, stdout) => { // eslint-disable-line handle-callback-err - source = stdout.replace(/\s+/, ''); - return sendReply(); + function getVersion(){ + return new Promise((resolve) => { + // figure it out from .git + const gitDir = path.resolve(__dirname, '..', '..', '.git'); + exec('git rev-parse HEAD', { cwd: gitDir }, (err, stdout) => { // eslint-disable-line handle-callback-err + commitHash = stdout.replace(/\s+/, ''); + const configPath = path.join(gitDir, 'config'); + const cmd = 'git config --get remote.origin.url'; + const env = Object.assign({}, process.env, { GIT_CONFIG: configPath }); + exec(cmd, { env }, (err, stdout) => { // eslint-disable-line handle-callback-err + source = stdout.replace(/\s+/, ''); + resolve(); + }); + }); }); - }); + } + + await getVersion(); + return getResp(); } }; diff --git a/lib/routes/uid.js b/lib/routes/uid.js index ca3b410..4a70f4e 100644 --- a/lib/routes/uid.js +++ b/lib/routes/uid.js @@ -7,10 +7,10 @@ module.exports = { strategy: 'oauth', scope: ['profile:uid'] }, - handler: function email(req, reply) { - reply({ + handler: async function email(req) { + return { uid: req.auth.credentials.user - }); + }; } }; diff --git a/lib/routing.js b/lib/routing.js index 753b6de..25fc833 100644 --- a/lib/routing.js +++ b/lib/routing.js @@ -12,66 +12,66 @@ module.exports = [ { method: 'GET', path: '/', - config: require('./routes/root') + options: require('./routes/root') }, { method: 'GET', path: '/__version__', - config: require('./routes/root') + options: require('./routes/root') }, { method: 'GET', path: '/__heartbeat__', - config: require('./routes/heartbeat') + options: require('./routes/heartbeat') }, { method: 'GET', path: '/__lbheartbeat__', - config: require('./routes/lbheartbeat') + options: require('./routes/lbheartbeat') }, { method: 'GET', path: v('/_core_profile'), - config: require('./routes/_core_profile') + options: require('./routes/_core_profile') }, { method: 'GET', path: v('/profile'), - config: require('./routes/profile') + options: require('./routes/profile') }, { method: 'GET', path: v('/email'), - config: require('./routes/email') + options: require('./routes/email') }, { method: 'GET', path: v('/uid'), - config: require('./routes/uid') + options: require('./routes/uid') }, { method: 'GET', path: v('/avatar'), - config: require('./routes/avatar/get') + options: require('./routes/avatar/get') }, { method: 'POST', path: v('/avatar/upload'), - config: require('./routes/avatar/upload') + options: require('./routes/avatar/upload') }, { method: 'DELETE', path: v('/avatar/{id?}'), - config: require('./routes/avatar/delete') + options: require('./routes/avatar/delete') }, { method: 'GET', path: v('/display_name'), - config: require('./routes/display_name/get') + options: require('./routes/display_name/get') }, { method: 'POST', path: v('/display_name'), - config: require('./routes/display_name/post') + options: require('./routes/display_name/post') } ]; diff --git a/lib/server/_static.js b/lib/server/_static.js index d58e51c..030758f 100644 --- a/lib/server/_static.js +++ b/lib/server/_static.js @@ -16,34 +16,28 @@ const DEFAULT_AVATAR = path.resolve(DEFAULT_AVATAR_DIR, 'default-profile.png'); const DEFAULT_AVATAR_LARGE = path.resolve(DEFAULT_AVATAR_DIR, 'default-profile_large.png'); const DEFAULT_AVATAR_SMALL = path.resolve(DEFAULT_AVATAR_DIR, 'default-profile_small.png'); -exports.create = function() { +exports.create = async function() { var server = new Hapi.Server({ + host: config.server.host, + port: config.server.port + 1, debug: false }); - server.register(Inert, function() {}); - - server.connection({ - host: config.server.host, - port: config.server.port + 1 - }); + await server.register(Inert); server.route({ method: 'GET', path: '/a/' + DEFAULT_AVATAR_ID + '{type?}', - handler: function (request, reply) { + handler: function (request, h) { switch (request.params.type) { case '': - reply.file(DEFAULT_AVATAR); - break; + return h.file(DEFAULT_AVATAR); case '_small': - reply.file(DEFAULT_AVATAR_SMALL); - break; + return h.file(DEFAULT_AVATAR_SMALL); case '_large': - reply.file(DEFAULT_AVATAR_LARGE); - break; + return h.file(DEFAULT_AVATAR_LARGE); default: - reply(Boom.notFound()); + return Boom.notFound(); } } }); @@ -58,11 +52,11 @@ exports.create = function() { } }); - server.on('log', function onLog(evt) { + server.events.on('log', function onLog(evt) { logger.verbose('hapi.server', evt); }); - server.on('request', function onRequest(req, evt) { + server.events.on('request', function onRequest(req, evt) { logger.verbose('hapi.request', evt); }); diff --git a/lib/server/web.js b/lib/server/web.js index ba44c94..bea32d1 100644 --- a/lib/server/web.js +++ b/lib/server/web.js @@ -5,6 +5,7 @@ const Hapi = require('hapi'); const Raven = require('raven'); const ScopeSet = require('fxa-shared').oauth.scopes; +const cloneDeep = require('lodash.clonedeep'); const AppError = require('../error'); const config = require('../config').getProperties(); @@ -32,41 +33,38 @@ function trimLocale(header) { // This is the webserver. It's what the outside always talks to. It // handles the whole Profile API. -exports.create = function createServer() { +exports.create = async function create() { var useRedis = config.serverCache.useRedis; var cache = { engine: useRedis ? require('catbox-redis') : require('catbox-memory') }; if (useRedis) { + cache.name = 'redisCache'; cache.host = config.serverCache.redis.host; cache.port = config.serverCache.redis.port; cache.partition = config.serverCache.redis.keyPrefix; } var isProd = config.env === 'production'; var server = new Hapi.Server({ + host: config.server.host, + port: config.server.port, cache: cache, debug: false, - connections: { - routes: { - cors: true, - security: { - hsts: { - maxAge: 15552000, - includeSubdomains: true - }, - xframe: true, - xss: true, - noOpen: false, - noSniff: true - } + routes: { + cors: true, + security: { + hsts: { + maxAge: 15552000, + includeSubdomains: true + }, + xframe: true, + xss: true, + noOpen: false, + noSniff: true } - } + }, }); - server.connection({ - host: config.server.host, - port: config.server.port - }); if (config.hpkpConfig && config.hpkpConfig.enabled) { var hpkpOptions = { @@ -83,14 +81,12 @@ exports.create = function createServer() { hpkpOptions.reportOnly = config.hpkpConfig.reportOnly; } - server.register({ - register: require('hapi-hpkp'), + + await server.register({ + plugin: require('hapi-hpkp'), options: hpkpOptions - }, function (err) { - if (err) { - throw err; - } }); + } // configure Sentry @@ -117,33 +113,42 @@ exports.create = function createServer() { server.auth.scheme('oauth', function() { return { - authenticate: function(req, reply) { + authenticate: async function(req, h) { var auth = req.headers.authorization; var url = config.oauth.url + '/verify'; logger.debug('auth', auth); if (! auth || auth.indexOf('Bearer') !== 0) { - return reply(AppError.unauthorized('Bearer token not provided')); + throw AppError.unauthorized('Bearer token not provided'); } var token = auth.split(' ')[1]; - request.post({ - url: url, - json: { - token: token, - email: false // disables email fetching of oauth server - } - }, function(err, resp, body) { - if (err || resp.statusCode >= 500) { - err = err || resp.statusMessage || 'unknown'; - logger.error('oauth.error', err); - return reply(AppError.oauthError(err)); - } - if (body.code >= 400) { - logger.debug('unauthorized', body); - return reply(AppError.unauthorized(body.message)); - } - logger.debug('auth.valid', body); - body.token = token; - reply.continue({ + + function makeReq() { + return new Promise((resolve, reject) => { + request.post({ + url: url, + json: { + token: token, + email: false // disables email fetching of oauth server + } + }, function (err, resp, body) { + if (err || resp.statusCode >= 500) { + err = err || resp.statusMessage || 'unknown'; + logger.error('oauth.error', err); + return reject(AppError.oauthError(err)); + } + if (body.code >= 400) { + logger.debug('unauthorized', body); + return reject(AppError.unauthorized(body.message)); + } + logger.debug('auth.valid', body); + body.token = token; + return resolve(body); + }); + }); + } + + return makeReq().then((body) => { + return h.authenticated({ credentials: body }); }); @@ -154,43 +159,43 @@ exports.create = function createServer() { server.auth.strategy('oauth', 'oauth'); // server method for caching profile - server.register({ + await server.register({ + name: 'profileCache', register: require('../profileCache'), options: config.serverCache - }, function (err) { - if (err) { - throw err; - } }); var routes = require('../routing'); if (isProd) { logger.info('production', 'Disabling response schema validation'); routes.forEach(function(route) { - delete route.config.response; + delete route.options.response; }); } // Expand the scope list on each route to include all super-scopes, // so that Hapi can easily check them via simple string comparison. - routes.forEach(function(route) { - var scope = route.config.auth && route.config.auth.scope; + routes = routes.map(function(routeDefinition) { + // create a copy of the route definition to avoid cross-unit test + // contamination since we make local changes to the definition object. + const route = cloneDeep(routeDefinition); + var scope = route.options.auth && route.options.auth.scope; if (scope) { - route.config.auth.scope = ScopeSet.fromArray(scope).getImplicantValues(); + route.options.auth.scope = ScopeSet.fromArray(scope).getImplicantValues(); } - }); - - routes.forEach(function(route) { - if (route.config.cache === undefined) { - route.config.cache = { + return route; + }).map(function(route) { + if (route.options.cache === undefined) { + route.options.cache = { otherwise: 'private, no-cache, no-store, must-revalidate' }; } + return route; }); - server.route(routes); + await server.route(routes); - server.ext('onPreAuth', function (request, reply) { + server.ext('onPreAuth', function (request, h) { // Construct source-ip-address chain for logging. var xff = (request.headers['x-forwarded-for'] || '').split(/\s*,\s*/); xff.push(request.info.remoteAddress); @@ -216,17 +221,16 @@ exports.create = function createServer() { logger.debug('auth', request.headers.authorization); logger.debug('type', request.headers['content-type'] || ''); } - reply.continue(); + return h.continue; }); - server.ext('onPreResponse', function(request, next) { + server.ext('onPreResponse', (request) => { var response = request.response; if (response.isBoom) { response = AppError.translate(response); } summary(request, response); - - next(response); + return response; }); return server; diff --git a/lib/server/worker.js b/lib/server/worker.js index b88e1bc..f0865a3 100644 --- a/lib/server/worker.js +++ b/lib/server/worker.js @@ -16,20 +16,18 @@ const SIZES = img.SIZES; exports.create = function() { var server = new Hapi.Server({ + host: config.worker.host, + port: config.worker.port, debug: false }); - server.connection({ - host: config.worker.host, - port: config.worker.port - }); server.route({ method: 'GET', path: '/__heartbeat__', config: { - handler: function upload(req, reply) { - reply({}); + handler: async function heartbeat() { + return {}; } } }); @@ -49,11 +47,11 @@ exports.create = function() { allow: ['image/png', 'image/jpeg'], maxBytes: config.img.uploads.maxSize }, - handler: function upload(req, reply) { + handler: async function upload(req) { logger.debug('worker.receive', { contentLength: req.headers['content-length'] }); - compute.image(req.params.id, req.payload).done(reply, reply); + return compute.image(req.params.id, req.payload); } } }); @@ -62,23 +60,23 @@ exports.create = function() { method: 'DELETE', path: '/a/{id}', config: { - handler: function delete_(req, reply) { - P.all(Object.keys(SIZES).map(function(name) { + handler: async function delete_(req) { + return P.all(Object.keys(SIZES).map(function(name) { if (name === 'default') { return req.params.id; } return req.params.id + '_' + name; - })).map(img.delete).done(reply, reply); + })).map(img.delete); } } }); - server.ext('onPreResponse', function(request, next) { + server.ext('onPreResponse', function(request) { var response = request.response; if (response.isBoom) { response = AppError.translate(response); } - next(response); + return response; }); return server; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 6e90c62..649d12e 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -14,9 +14,9 @@ } }, "JSONStream": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.3.tgz", - "integrity": "sha512-3Sp6WZZ/lXl+nTDoGpGWHEpTnnC6X5fnkolYZR6nwIfzbxxvA8utPWe1gCt7i0m9uVGsSz2IS8K8mJ7HmlduMg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.4.tgz", + "integrity": "sha512-Y7vfi3I5oMOYIr+WxV8NZxDSwcbNgzdKYsTNInmycOq9bUYwGg9ryu57Wg5NLmCjqdFPNUmpMBo3kSJN9tCbXg==", "dev": true, "requires": { "jsonparse": "^1.2.0", @@ -30,22 +30,12 @@ "dev": true }, "accept": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/accept/-/accept-2.1.4.tgz", - "integrity": "sha1-iHr1TO7lx/RDBGGXHsQAxh0JrLs=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/accept/-/accept-3.0.2.tgz", + "integrity": "sha512-bghLXFkCOsC1Y2TZ51etWfKDs6q249SAoHTZVfzWWdlZxoij+mgkj9AmUJWQpDY48TfnrTDIe43Xem4zdMe7mQ==", "requires": { - "boom": "5.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } + "boom": "7.x.x", + "hoek": "5.x.x" } }, "accept-language": { @@ -125,22 +115,11 @@ "dev": true }, "ammo": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/ammo/-/ammo-2.0.4.tgz", - "integrity": "sha1-v4CqshFpjqePY+9efxE91dnokX8=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ammo/-/ammo-3.0.1.tgz", + "integrity": "sha512-4UqoM8xQjwkQ78oiU4NbBK0UgYqeKMAKmwE4ec7Rz3rGU8ZEBFxzgF2sUYKOAlqIXExBDYLN6y1ShF5yQ4hwLQ==", "requires": { - "boom": "5.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } + "hoek": "5.x.x" } }, "ansi-escapes": { @@ -223,9 +202,12 @@ "dev": true }, "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } }, "assert-plus": { "version": "1.0.0", @@ -265,14 +247,14 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "b64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/b64/-/b64-3.0.3.tgz", - "integrity": "sha512-Pbeh0i6OLubPJdIdCepn8ZQHwN2MWznZHbHABSTEfQ706ie+yuxNSaPdqX1xRatT6WanaS1EazMiSg0NUW2XxQ==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/b64/-/b64-4.0.0.tgz", + "integrity": "sha512-EhmUQodKB0sdzPPrbIWbGqA5cQeTWxYrAgNeeT1rLZWtD3tbNTnphz8J4vkXI3cPgBNlXBjzEbzDzq0Nwi4f9A==" }, "balanced-match": { "version": "1.0.0", @@ -293,6 +275,11 @@ "tweetnacl": "^0.14.3" } }, + "big-time": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/big-time/-/big-time-2.0.1.tgz", + "integrity": "sha1-aMffjcMPl+lT8lpnp2rJcTwWyd4=" + }, "bignumber.js": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.3.0.tgz", @@ -304,11 +291,20 @@ "integrity": "sha1-tzHd9I4t077awudeEhWhG8uR+gc=" }, "boom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.0.0.tgz", - "integrity": "sha1-fllGkmTq3bdP7fvBsWUk1pppRXc=", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-7.2.0.tgz", + "integrity": "sha1-K/8kpVVldn/ehp7ICDF+sQxI6WY=", "requires": { - "hoek": "4.x.x" + "hoek": "5.x.x" + } + }, + "bounce": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bounce/-/bounce-1.2.0.tgz", + "integrity": "sha512-8syCGe8B2/WC53118/F/tFy5aW00j+eaGPXmAUP7iBhxc+EBZZxS1vKelWyBCH6IqojgS2t1gF0glH30qAJKEw==", + "requires": { + "boom": "7.x.x", + "hoek": "5.x.x" } }, "brace-expansion": { @@ -332,9 +328,9 @@ "integrity": "sha1-o0/Kie5qQdMmFmhl4Qg/oRLONGg=" }, "buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" }, "builtin-modules": { "version": "1.1.1", @@ -343,22 +339,12 @@ "dev": true }, "call": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/call/-/call-4.0.2.tgz", - "integrity": "sha1-33b19R7o3Ui4VqyEAPfmnm1zmcQ=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/call/-/call-5.0.1.tgz", + "integrity": "sha512-ollfFPSshiuYLp7AsrmpkQJ/PxCi6AzV81rCjBwWhyF2QGyUY/vPDMzoh4aUcWyucheRglG2LaS5qkIEfLRh6A==", "requires": { - "boom": "5.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } + "boom": "7.x.x", + "hoek": "5.x.x" } }, "caller-path": { @@ -405,51 +391,33 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "catbox": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/catbox/-/catbox-7.1.5.tgz", - "integrity": "sha512-4fui5lELzqZ+9cnaAP/BcqXTH6LvWLBRtFhJ0I4FfgfXiSaZcf6k9m9dqOyChiTxNYtvLk7ZMYSf7ahMq3bf5A==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/catbox/-/catbox-10.0.2.tgz", + "integrity": "sha512-cTQTQeKMhWHU0lX8CADE3g1koGJu+AlcWFzAjMX/8P+XbkScGYw3tJsQpe2Oh8q68vOQbOLacz9k+6V/F3Z9DA==", "requires": { - "boom": "5.x.x", - "hoek": "4.x.x", - "joi": "10.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "joi": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-10.6.0.tgz", - "integrity": "sha512-hBF3LcqyAid+9X/pwg+eXjD2QBZI5eXnBFJYaAkH4SK3mp9QSRiiQnDYlmlz5pccMvnLcJRS4whhDOTCkmsAdQ==", - "requires": { - "hoek": "4.x.x", - "isemail": "2.x.x", - "items": "2.x.x", - "topo": "2.x.x" - } - } + "boom": "7.x.x", + "bounce": "1.x.x", + "hoek": "5.x.x", + "joi": "13.x.x" } }, "catbox-memory": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/catbox-memory/-/catbox-memory-2.0.4.tgz", - "integrity": "sha1-Qz4lWQLK9UIz0ShkKcj03xToItU=", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/catbox-memory/-/catbox-memory-3.1.2.tgz", + "integrity": "sha512-lhWtutLVhsq3Mucxk2McxBPPibJ34WcHuWFz3xqub9u9Ve/IQYpZv3ijLhQXfQped9DXozURiaq9O3aZpP91eg==", "requires": { - "hoek": "4.x.x" + "big-time": "2.x.x", + "boom": "7.x.x", + "hoek": "5.x.x" } }, "catbox-redis": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/catbox-redis/-/catbox-redis-3.0.1.tgz", - "integrity": "sha1-DS8Nfwxi+AgfcIU79GY76Ryl/9E=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/catbox-redis/-/catbox-redis-4.1.0.tgz", + "integrity": "sha512-QvoI6BRqHh/a3auOe+BAe5g/VKxmmdIgXNZkUjA9rpJFBtW6QFkRYkHIQRcTV9YswAW44dRl9+/xPEZttBYeQg==", "requires": { - "hoek": "4.x.x", - "ioredis": "2.x.x" + "hoek": "5.x.x", + "ioredis": "3.x.x" } }, "center-align": { @@ -650,21 +618,11 @@ } }, "content": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/content/-/content-3.0.7.tgz", - "integrity": "sha512-LXtnSnvE+Z1Cjpa3P9gh9kb396qV4MqpfwKy777BOSF8n6nw2vAi03tHNl0/XRqZUyzVzY/+nMXOZVnEapWzdg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/content/-/content-4.0.5.tgz", + "integrity": "sha512-wDP6CTWDpwCf791fNxlCCkZGRkrNzSEU/8ju9Hnr3Uc5mF/gFR5W+fcoGm6zUSlVPdSXYn5pCbySADKj7YM4Cg==", "requires": { - "boom": "5.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } + "boom": "7.x.x" } }, "conventional-changelog": { @@ -783,21 +741,11 @@ } }, "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.2.tgz", + "integrity": "sha512-U2ALcoAHvA1oO2xOreyHvtkQ+IELqDG2WVWRI1GH/XEmmfGIOalnM5MU5Dd2ITyWfr3m6kNqXiy8XuYyd4wKJw==", "requires": { - "boom": "5.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } + "boom": "7.x.x" } }, "currently-unhandled": { @@ -932,6 +880,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "denque": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.3.0.tgz", + "integrity": "sha512-4SRaSj+PqmrS1soW5/Avd7eJIM2JJIqLLmwhRqIGleZM/8KwZq80njbSS2Iqas+6oARkSkLDHEk4mm78q3JlIg==" + }, "depd": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", @@ -970,18 +923,14 @@ "is-obj": "^1.0.0" } }, - "double-ended-queue": { - "version": "2.1.0-0", - "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", - "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" - }, "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { - "jsbn": "~0.1.0" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "error-ex": { @@ -994,9 +943,9 @@ } }, "es5-ext": { - "version": "0.10.45", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz", - "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", + "version": "0.10.46", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz", + "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==", "dev": true, "requires": { "es6-iterator": "~2.0.3", @@ -1931,66 +1880,49 @@ } }, "hapi": { - "version": "16.6.3", - "resolved": "https://registry.npmjs.org/hapi/-/hapi-16.6.3.tgz", - "integrity": "sha512-Fe1EtSlRWdez9c1sLDrHZYxpsp3IddwtUWp7y65TCBW5CMcBP98X4WnoBJZTGsDZnk/FDkRyEMhUVsC9qysDPg==", - "requires": { - "accept": "^2.1.4", - "ammo": "^2.0.4", - "boom": "^5.2.0", - "call": "^4.0.2", - "catbox": "^7.1.5", - "catbox-memory": "^2.0.4", - "cryptiles": "^3.1.2", - "heavy": "^4.0.4", - "hoek": "^4.2.0", - "iron": "^4.0.5", - "items": "^2.1.1", - "joi": "^11.1.0", - "mimos": "^3.0.3", - "podium": "^1.3.0", - "shot": "^3.4.2", - "statehood": "^5.0.3", - "subtext": "^5.0.0", - "topo": "^2.0.2" + "version": "17.5.2", + "resolved": "https://registry.npmjs.org/hapi/-/hapi-17.5.2.tgz", + "integrity": "sha512-UxMKYzrjfXlcztJQPEB3os5rM3SKgSQVxoOym4KI3JdP4pxl5WUdZYF8it4Kga2OMTGwB+ZTy+DU9b/oDaQHRQ==", + "requires": { + "accept": "3.x.x", + "ammo": "3.x.x", + "boom": "7.x.x", + "bounce": "1.x.x", + "call": "5.x.x", + "catbox": "10.x.x", + "catbox-memory": "3.x.x", + "heavy": "6.x.x", + "hoek": "5.x.x", + "joi": "13.x.x", + "mimos": "4.x.x", + "podium": "3.x.x", + "shot": "4.x.x", + "statehood": "6.x.x", + "subtext": "6.x.x", + "teamwork": "3.x.x", + "topo": "3.x.x" + } + }, + "hapi-hpkp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hapi-hpkp/-/hapi-hpkp-2.0.0.tgz", + "integrity": "sha512-Kko4pgRWp3Q5VAZySU7IOYv1RJ3s8BXtmYtV44BaWINWQgt5vsDuKiKIZBzO2X8hphCkGw0tdkZFu1yrhIUscg==", + "requires": { + "joi": "13.3.0" }, "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "isemail": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.1.3.tgz", - "integrity": "sha512-5xbsG5wYADIcB+mfLsd+nst1V/D+I7EU7LEZPo2GOIMu4JzfcRs5yQoypP4avA7QtUqgxYLKBYNv4IdzBmbhdw==", - "requires": { - "punycode": "2.x.x" - } - }, "joi": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-11.4.0.tgz", - "integrity": "sha512-O7Uw+w/zEWgbL6OcHbyACKSj0PkQeUgmehdoXVSxt92QFCq4+1390Rwh5moI2K/OgC7D8RHRZqHZxT2husMJHA==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-13.3.0.tgz", + "integrity": "sha512-iF6jEYVfBIoYXztYymia1JfuoVbxBNuOcwdbsdoGin9/jjhBLhonKmfTQOvePss8r8v4tU4JOcNmYPHZzKEFag==", "requires": { - "hoek": "4.x.x", + "hoek": "5.x.x", "isemail": "3.x.x", - "topo": "2.x.x" + "topo": "3.x.x" } } } }, - "hapi-hpkp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hapi-hpkp/-/hapi-hpkp-1.0.0.tgz", - "integrity": "sha1-txskDnOv/ZHFzT52cYr6DmlBwAM=", - "requires": { - "joi": "9.0.4" - } - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -2028,49 +1960,61 @@ "cryptiles": "3.x.x", "hoek": "4.x.x", "sntp": "2.x.x" - } - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", - "dev": true - }, - "heavy": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/heavy/-/heavy-4.0.4.tgz", - "integrity": "sha1-NskTNsAMz+hSyqTRUwhjNc0vAOk=", - "requires": { - "boom": "5.x.x", - "hoek": "4.x.x", - "joi": "10.x.x" }, "dependencies": { "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", "requires": { "hoek": "4.x.x" } }, - "joi": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-10.6.0.tgz", - "integrity": "sha512-hBF3LcqyAid+9X/pwg+eXjD2QBZI5eXnBFJYaAkH4SK3mp9QSRiiQnDYlmlz5pccMvnLcJRS4whhDOTCkmsAdQ==", + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", "requires": { - "hoek": "4.x.x", - "isemail": "2.x.x", - "items": "2.x.x", - "topo": "2.x.x" + "boom": "5.x.x" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "requires": { + "hoek": "4.x.x" + } + } } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" } } }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "heavy": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/heavy/-/heavy-6.1.0.tgz", + "integrity": "sha512-TKS9DC9NOTGulHQI31Lx+bmeWmNOstbJbGMiN3pX6bF+Zc2GKSpbbym4oasNnB6yPGkqJ9TQXXYDGohqNSJRxA==", + "requires": { + "boom": "7.x.x", + "hoek": "5.x.x", + "joi": "13.x.x" + } + }, "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", + "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==" }, "hooker": { "version": "0.2.3", @@ -2135,35 +2079,16 @@ } }, "inert": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/inert/-/inert-4.0.2.tgz", - "integrity": "sha1-8mCUmI5lP4HISmkGZHgVRvjXWSg=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/inert/-/inert-5.1.0.tgz", + "integrity": "sha512-5rJZbezGEkBN4QrP/HEEwsQ0N+7YzqDZrvBZrE7B0CrNY6I4XKI434aL3UNLCmbI4HzPGQs7Ae/4h1tiTMJ6Wg==", "requires": { - "ammo": "2.x.x", - "boom": "3.x.x", - "hoek": "4.x.x", - "items": "2.x.x", - "joi": "9.x.x", - "lru-cache": "4.0.x" - }, - "dependencies": { - "boom": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/boom/-/boom-3.2.2.tgz", - "integrity": "sha1-DwzF0ErcUAO4x9cfQsynJx/vDng=", - "requires": { - "hoek": "4.x.x" - } - }, - "lru-cache": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", - "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", - "requires": { - "pseudomap": "^1.0.1", - "yallist": "^2.0.0" - } - } + "ammo": "3.x.x", + "boom": "7.x.x", + "bounce": "1.x.x", + "hoek": "5.x.x", + "joi": "13.x.x", + "lru-cache": "4.1.x" } }, "inflight": { @@ -2210,25 +2135,19 @@ } }, "insist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/insist/-/insist-1.0.0.tgz", - "integrity": "sha1-W+Sa55tzM3XgsXLxhLklxfxETHc=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/insist/-/insist-1.0.1.tgz", + "integrity": "sha1-ITdKECnUoTpidEEV38LTMTQYldQ=", "dev": true, "requires": { - "esprima": "^2.0.0", - "stack-trace": "^0.0.7" + "esprima": "^4.0.0", + "stack-trace": "^0.0.10" }, "dependencies": { "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", - "dev": true - }, - "stack-trace": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.7.tgz", - "integrity": "sha1-xy4Il0T8Nln1CM3ONiGvVjTsD/8=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true } } @@ -2247,45 +2166,43 @@ } }, "ioredis": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-2.5.0.tgz", - "integrity": "sha1-+2/fChp+CXRhTGe25eETCKjPlbk=", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-3.2.2.tgz", + "integrity": "sha512-g+ShTQYLsCcOUkNOK6CCEZbj3aRDVPw3WOwXk+LxlUKvuS9ujEqP2MppBHyRVYrNNFW/vcPaTBUZ2ctGNSiOCA==", "requires": { "bluebird": "^3.3.4", "cluster-key-slot": "^1.0.6", - "debug": "^2.2.0", - "double-ended-queue": "^2.1.0-0", + "debug": "^2.6.9", + "denque": "^1.1.0", "flexbuffer": "0.0.6", - "lodash": "^4.8.2", + "lodash.assign": "^4.2.0", + "lodash.bind": "^4.2.1", + "lodash.clone": "^4.5.0", + "lodash.clonedeep": "^4.5.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.foreach": "^4.5.0", + "lodash.isempty": "^4.4.0", + "lodash.keys": "^4.2.0", + "lodash.noop": "^3.0.1", + "lodash.partial": "^4.2.1", + "lodash.pick": "^4.4.0", + "lodash.sample": "^4.2.1", + "lodash.shuffle": "^4.2.0", + "lodash.values": "^4.3.0", "redis-commands": "^1.2.0", - "redis-parser": "^1.3.0" - }, - "dependencies": { - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - } + "redis-parser": "^2.4.0" } }, "iron": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/iron/-/iron-4.0.5.tgz", - "integrity": "sha1-TwQszri5c480a1mqc0yDqJvDFCg=", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/iron/-/iron-5.0.4.tgz", + "integrity": "sha512-7iQ5/xFMIYaNt9g2oiNiWdhrOTdRUMFaWENUd0KghxwPUhrIH8DUY8FEyLNTTzf75jaII+jMexLdY/2HfV61RQ==", "requires": { - "boom": "5.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } + "boom": "7.x.x", + "cryptiles": "4.x.x", + "hoek": "5.x.x" } }, "irregular-plurals": { @@ -2340,9 +2257,9 @@ "dev": true }, "is-my-json-valid": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", - "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz", + "integrity": "sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==", "dev": true, "requires": { "generate-function": "^2.0.0", @@ -2432,9 +2349,12 @@ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, "isemail": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-2.2.1.tgz", - "integrity": "sha1-A1PT2aYpUQgMJiwqoKQrjqjp4qY=" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.1.3.tgz", + "integrity": "sha512-5xbsG5wYADIcB+mfLsd+nst1V/D+I7EU7LEZPo2GOIMu4JzfcRs5yQoypP4avA7QtUqgxYLKBYNv4IdzBmbhdw==", + "requires": { + "punycode": "2.x.x" + } }, "isexe": { "version": "2.0.0", @@ -2446,26 +2366,19 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, - "items": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/items/-/items-2.1.1.tgz", - "integrity": "sha1-i9FtnIOxlSneWuoyGsqtp4NkoZg=" - }, "jmespath": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" }, "joi": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/joi/-/joi-9.0.4.tgz", - "integrity": "sha1-iNZIkJFavrEnzXVwJxFtUN8+aN8=", + "version": "13.5.2", + "resolved": "https://registry.npmjs.org/joi/-/joi-13.5.2.tgz", + "integrity": "sha512-3HrFXLC57iU5CzYth3cJRdYEo4/Dr+tXmCQ+BHyiTTKnKxJ9ICkI/WJGPwUUXj3dWA4tO2hwZO5oCdBNhAYuRg==", "requires": { - "hoek": "4.x.x", - "isemail": "2.x.x", - "items": "2.x.x", - "moment": "2.x.x", - "topo": "2.x.x" + "hoek": "5.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" } }, "js-yaml": { @@ -2666,6 +2579,19 @@ "dev": true, "requires": { "lodash.keys": "^3.0.0" + }, + "dependencies": { + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + } } }, "lodash._baseisequal": { @@ -2677,6 +2603,19 @@ "lodash.isarray": "^3.0.0", "lodash.istypedarray": "^3.0.0", "lodash.keys": "^3.0.0" + }, + "dependencies": { + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + } } }, "lodash._basetostring": { @@ -2721,11 +2660,36 @@ "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", "dev": true }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=" + }, + "lodash.bind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" + }, + "lodash.clone": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", + "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=" + }, "lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=" + }, "lodash.escape": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", @@ -2735,6 +2699,16 @@ "lodash._root": "^3.0.0" } }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" + }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -2747,6 +2721,11 @@ "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", "dev": true }, + "lodash.isempty": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", + "integrity": "sha1-b4bL7di+TsmHvpqvM8loTbGzHn4=" + }, "lodash.istypedarray": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz", @@ -2754,15 +2733,9 @@ "dev": true }, "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-4.2.0.tgz", + "integrity": "sha1-oIYCrBLk+4P5H8H7ejYKTZujUgU=" }, "lodash.map": { "version": "3.1.4", @@ -2775,8 +2748,26 @@ "lodash._baseeach": "^3.0.0", "lodash.isarray": "^3.0.0", "lodash.keys": "^3.0.0" + }, + "dependencies": { + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + } } }, + "lodash.noop": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-3.0.1.tgz", + "integrity": "sha1-OBiPTWUKOkdCWEObluxFsyYXEzw=" + }, "lodash.pairs": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash.pairs/-/lodash.pairs-3.0.1.tgz", @@ -2784,14 +2775,47 @@ "dev": true, "requires": { "lodash.keys": "^3.0.0" + }, + "dependencies": { + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + } } }, + "lodash.partial": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.partial/-/lodash.partial-4.2.1.tgz", + "integrity": "sha1-SfPYz9qjv/izqR0SfpIyRUGJYdQ=" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" + }, "lodash.restparam": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", "dev": true }, + "lodash.sample": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.sample/-/lodash.sample-4.2.1.tgz", + "integrity": "sha1-XkKRsMdT+hq+sKq4+ynfG2bwf20=" + }, + "lodash.shuffle": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.shuffle/-/lodash.shuffle-4.2.0.tgz", + "integrity": "sha1-FFtQU8+HX29cKjP0i26ZSMbse0s=" + }, "lodash.template": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", @@ -2807,6 +2831,19 @@ "lodash.keys": "^3.0.0", "lodash.restparam": "^3.0.0", "lodash.templatesettings": "^3.0.0" + }, + "dependencies": { + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "^3.0.0", + "lodash.isarguments": "^3.0.0", + "lodash.isarray": "^3.0.0" + } + } } }, "lodash.templatesettings": { @@ -2819,6 +2856,11 @@ "lodash.escape": "^3.0.0" } }, + "lodash.values": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz", + "integrity": "sha1-o6bCsOvsxcLLocF+bmIP6BtT00c=" + }, "lolex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", @@ -2898,11 +2940,11 @@ } }, "mimos": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/mimos/-/mimos-3.0.3.tgz", - "integrity": "sha1-uRCQcq03jCty9qAQHEPd+ys2ZB8=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimos/-/mimos-4.0.0.tgz", + "integrity": "sha512-JvlvRLqGIlk+AYypWrbrDmhsM+6JVx/xBM5S3AMwTBz1trPCEoPN/swO2L4Wu653fL7oJdgk8DMQyG/Gq3JkZg==", "requires": { - "hoek": "4.x.x", + "hoek": "5.x.x", "mime-db": "1.x.x" } }, @@ -3138,12 +3180,12 @@ "dev": true }, "nigel": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/nigel/-/nigel-2.0.2.tgz", - "integrity": "sha1-k6GGb7DFLYc5CqdeKxYfS1x15bE=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nigel/-/nigel-3.0.1.tgz", + "integrity": "sha512-kCVtUG9JyD//tsYrZY+/Y+2gUrANVSba8y23QkM5Znx0FOxlnl9Z4OVPBODmstKWTOvigfTO+Va1VPOu3eWSOQ==", "requires": { - "hoek": "4.x.x", - "vise": "2.x.x" + "hoek": "5.x.x", + "vise": "3.x.x" } }, "nock": { @@ -6400,25 +6442,15 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pez": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/pez/-/pez-2.1.5.tgz", - "integrity": "sha1-XsLMYlAMw+tCNtSkFM9aF7XrUAc=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pez/-/pez-4.0.2.tgz", + "integrity": "sha512-HuPxmGxHsEFPWhdkwBs2gIrHhFqktIxMtudISTFN95RQ85ZZAOl8Ki6u3nnN/X8OUaGlIGldk/l8p2IR4/i76w==", "requires": { - "b64": "3.x.x", - "boom": "5.x.x", - "content": "3.x.x", - "hoek": "4.x.x", - "nigel": "2.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } + "b64": "4.x.x", + "boom": "7.x.x", + "content": "4.x.x", + "hoek": "5.x.x", + "nigel": "3.x.x" } }, "pify": { @@ -6473,26 +6505,12 @@ "dev": true }, "podium": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/podium/-/podium-1.3.0.tgz", - "integrity": "sha512-ZIujqk1pv8bRZNVxwwwq0BhXilZ2udycQT3Kp8ah3f3TcTmVg7ILJsv/oLf47gRa2qeiP584lNq+pfvS9U3aow==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/podium/-/podium-3.1.2.tgz", + "integrity": "sha512-18VrjJAduIdPv7d9zWsfmKxTj3cQTYC5Pv5gtKxcWujYBpGbV+mhNSPYhlHW5xeWoazYyKfB9FEsPT12r5rY1A==", "requires": { - "hoek": "4.x.x", - "items": "2.x.x", - "joi": "10.x.x" - }, - "dependencies": { - "joi": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-10.6.0.tgz", - "integrity": "sha512-hBF3LcqyAid+9X/pwg+eXjD2QBZI5eXnBFJYaAkH4SK3mp9QSRiiQnDYlmlz5pccMvnLcJRS4whhDOTCkmsAdQ==", - "requires": { - "hoek": "4.x.x", - "isemail": "2.x.x", - "items": "2.x.x", - "topo": "2.x.x" - } - } + "hoek": "5.x.x", + "joi": "13.x.x" } }, "poolee": { @@ -6660,9 +6678,9 @@ "integrity": "sha512-foGF8u6MXGFF++1TZVC6icGXuMYPftKXt1FBT2vrfU9ZATNtZJ8duRC5d1lEfE8hyVe3jhelHGB91oB7I6qLsA==" }, "redis-parser": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-1.3.0.tgz", - "integrity": "sha1-gG6+e7+3005NfB6e8oLvz60EEmo=" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" }, "repeat-string": { "version": "1.6.1", @@ -6847,25 +6865,12 @@ "dev": true }, "shot": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/shot/-/shot-3.4.2.tgz", - "integrity": "sha1-Hlw/bysmZJrcQvfrNQIUpaApHWc=", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/shot/-/shot-4.0.5.tgz", + "integrity": "sha1-x+dFXRHWD2ts08Q+FaO0McF+VWY=", "requires": { - "hoek": "4.x.x", - "joi": "10.x.x" - }, - "dependencies": { - "joi": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-10.6.0.tgz", - "integrity": "sha512-hBF3LcqyAid+9X/pwg+eXjD2QBZI5eXnBFJYaAkH4SK3mp9QSRiiQnDYlmlz5pccMvnLcJRS4whhDOTCkmsAdQ==", - "requires": { - "hoek": "4.x.x", - "isemail": "2.x.x", - "items": "2.x.x", - "topo": "2.x.x" - } - } + "hoek": "5.x.x", + "joi": "13.x.x" } }, "signal-exit": { @@ -6898,6 +6903,13 @@ "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", "requires": { "hoek": "4.x.x" + }, + "dependencies": { + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + } } }, "source-map": { @@ -6992,37 +7004,16 @@ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, "statehood": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/statehood/-/statehood-5.0.3.tgz", - "integrity": "sha512-YrPrCt10t3ImH/JMO5szSwX7sCm8HoqVl3VFLOa9EZ1g/qJx/ZmMhN+2uzPPB/vaU6hpkJpXxcBWsgIkkG+MXA==", + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/statehood/-/statehood-6.0.6.tgz", + "integrity": "sha512-jR45n5ZMAkasw0xoE9j9TuLmJv4Sa3AkXe+6yIFT6a07kXYHgSbuD2OVGECdZGFxTmvNqLwL1iRIgvq6O6rq+A==", "requires": { - "boom": "5.x.x", - "cryptiles": "3.x.x", - "hoek": "4.x.x", - "iron": "4.x.x", - "items": "2.x.x", - "joi": "10.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - }, - "joi": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-10.6.0.tgz", - "integrity": "sha512-hBF3LcqyAid+9X/pwg+eXjD2QBZI5eXnBFJYaAkH4SK3mp9QSRiiQnDYlmlz5pccMvnLcJRS4whhDOTCkmsAdQ==", - "requires": { - "hoek": "4.x.x", - "isemail": "2.x.x", - "items": "2.x.x", - "topo": "2.x.x" - } - } + "boom": "7.x.x", + "bounce": "1.x.x", + "cryptiles": "4.x.x", + "hoek": "5.x.x", + "iron": "5.x.x", + "joi": "13.x.x" } }, "stream-to-array": { @@ -7092,25 +7083,15 @@ "dev": true }, "subtext": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/subtext/-/subtext-5.0.0.tgz", - "integrity": "sha512-2nXG1G1V+K64Z20cQII7k0s38J2DSycMXBLMAk9RXUFG0uAkAbLSVoa88croX9VhTdBCJbLAe9g6LmzKwpJhhQ==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/subtext/-/subtext-6.0.7.tgz", + "integrity": "sha512-IcJUvRjeR+NB437Iq+LORFNJW4L6Knqkj3oQrBrkdhIaS2VKJvx/9aYEq7vi+PEx5/OuehOL/40SkSZotLi/MA==", "requires": { - "boom": "5.x.x", - "content": "3.x.x", - "hoek": "4.x.x", - "pez": "2.x.x", - "wreck": "12.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } + "boom": "7.x.x", + "content": "4.x.x", + "hoek": "5.x.x", + "pez": "4.x.x", + "wreck": "14.x.x" } }, "supports-color": { @@ -7186,6 +7167,11 @@ } } }, + "teamwork": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/teamwork/-/teamwork-3.0.1.tgz", + "integrity": "sha512-hEkJIpDOfOYe9NYaLFk00zQbzZeKNCY8T2pRH3I13Y1mJwxaSQ6NEsjY5rCp+11ezCiZpWGoGFTbOuhg4qKevQ==" + }, "tempfile": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-1.1.1.tgz", @@ -7290,11 +7276,11 @@ "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, "topo": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz", - "integrity": "sha1-zVYVdSU5BXwNwEkaYhw7xvvh0YI=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.0.tgz", + "integrity": "sha512-Tlu1fGlR90iCdIPURqPiufqAlCZYzLjHYVVbcFWDMcX7+tK8hdZWAfsMrD/pBul9jqHHwFjNdf1WaxA9vTRRhw==", "requires": { - "hoek": "4.x.x" + "hoek": "5.x.x" } }, "tough-cookie": { @@ -7426,9 +7412,9 @@ "integrity": "sha1-Zyj8BFnEUNeWqZwxg3VpvfZy1yg=" }, "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", @@ -7461,11 +7447,11 @@ } }, "vise": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/vise/-/vise-2.0.2.tgz", - "integrity": "sha1-awjo+0y3bjpQzW3Q7DczjoEaDTk=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vise/-/vise-3.0.0.tgz", + "integrity": "sha512-kBFZLmiL1Vm3rHXphkhvvAcsjgeQXRrOFCbJb0I50YZZP4HGRNH+xGzK3matIMcpbsfr3I02u9odj4oCD0TWgA==", "requires": { - "hoek": "4.x.x" + "hoek": "5.x.x" } }, "vows": { @@ -7502,22 +7488,12 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "wreck": { - "version": "12.5.1", - "resolved": "https://registry.npmjs.org/wreck/-/wreck-12.5.1.tgz", - "integrity": "sha512-l5DUGrc+yDyIflpty1x9XuMj1ehVjC/dTbF3/BasOO77xk0EdEa4M/DuOY8W88MQDAD0fEDqyjc8bkIMHd2E9A==", + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/wreck/-/wreck-14.0.2.tgz", + "integrity": "sha512-QCm3omWNJUseqrSzwX2QZi1rBbmCfbFHJAXputLLyZ37VSiFnSYQB0ms/mPnSvrlIu7GVm89Y/gBNhSY26uVIQ==", "requires": { - "boom": "5.x.x", - "hoek": "4.x.x" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.x.x" - } - } + "boom": "7.x.x", + "hoek": "5.x.x" } }, "write": { diff --git a/package.json b/package.json index ffa7166..e4e99cd 100644 --- a/package.json +++ b/package.json @@ -13,20 +13,21 @@ "dependencies": { "aws-sdk": "2.4.7", "bluebird": "3.4.1", - "boom": "4.0.0", + "boom": "7.2.0", "buf": "0.1.0", - "catbox-memory": "2.0.4", - "catbox-redis": "3.0.1", + "catbox-memory": "3.1.2", + "catbox-redis": "4.1.0", "checksum": "0.1.1", "compute-cluster": "0.0.9", "convict": "4.0.2", "fxa-notifier-aws": "1.0.0", "fxa-shared": "1.0.13", "gm-reloaded": "1.24.0", - "hapi": "16.6.3", - "hapi-hpkp": "1.0.0", - "inert": "4.0.2", - "joi": "9.0.4", + "hapi": "17.5.2", + "hapi-hpkp": "2.0.0", + "inert": "5.1.0", + "joi": "13.5.2", + "lodash.clonedeep": "4.5.0", "mozlog": "2.2.0", "mysql": "2.11.1", "mysql-patcher": "0.7.0", @@ -47,7 +48,7 @@ "grunt-eslint": "18.0.0", "grunt-mocha-test": "0.12.7", "grunt-nsp": "2.3.1", - "insist": "1.0.0", + "insist": "1.0.1", "load-grunt-tasks": "3.5.0", "mkdirp": "0.5.1", "mocha": "4.0.1", diff --git a/test/api.js b/test/api.js index 28d332d..9314127 100644 --- a/test/api.js +++ b/test/api.js @@ -62,6 +62,8 @@ afterEach(function() { }); describe('/profile', function() { + beforeEach(() => Server.server()); + var tok = token(); var user = uid(); @@ -410,6 +412,7 @@ describe('/email', function() { describe('/_core_profile', () => { const tok = token(); + beforeEach(() => Server.server()); it('should be hidden from external callers by default', () => { return Server.api.get({ @@ -547,6 +550,7 @@ describe('/_core_profile', () => { describe('/uid', function() { var tok = token(); + beforeEach(() => Server.server()); it('should return an uid', function() { mock.tokenGood(); @@ -586,6 +590,8 @@ describe('/avatar', function() { var id1 = avatarId(); var id2 = avatarId(); + beforeEach(() => Server.server()); + describe('GET', function() { before(function() { var grav1 = GRAVATAR.slice(0, -1) + '1'; @@ -661,6 +667,7 @@ describe('/avatar', function() { }); describe('upload', function() { + beforeEach(() => Server.server()); it('should upload a new avatar', function() { this.slow(2000); @@ -787,7 +794,7 @@ describe('/avatar', function() { describe('DELETE', function() { var user = uid(); - + beforeEach(() => Server.server()); it('should require :write scope', function() { mock.token({ @@ -851,7 +858,10 @@ describe('/avatar', function() { describe('uploaded', function() { var s3url; var id; - beforeEach(function() { + + beforeEach(async function() { + await Server.server(); + mock.token({ user: user, scope: ['profile:avatar:write'] @@ -929,6 +939,7 @@ describe('/avatar', function() { describe('/display_name', function() { var tok = token(); + beforeEach(() => Server.server()); describe('GET', function() { it('should return a displayName', function() { @@ -989,6 +1000,8 @@ describe('/display_name', function() { }); describe('POST', function() { + beforeEach(() => Server.server()); + it('should post a new display name', function() { var NAME = 'Spock'; mock.token({ @@ -1082,7 +1095,7 @@ describe('/display_name', function() { displayName: '' }, headers: { - authorization: 'Bearer ' + tok + authorizatsion: 'Bearer ' + tok } }); }).then(function(res) { diff --git a/test/events.js b/test/events.js index 0fa8592..0d16277 100644 --- a/test/events.js +++ b/test/events.js @@ -34,6 +34,10 @@ const SIZE_SUFFIXES = Object.keys(SIZES).map(function(val) { /*global describe,it,beforeEach,afterEach*/ +beforeEach(function () { + return Server.server(); +}); + afterEach(function() { mock.done(); }); @@ -142,9 +146,7 @@ describe('events', function() { }; } beforeEach(function () { - Server.server.methods.profileCache.drop = sinon.spy(function (uid, cb) { - cb(); - }); + Server.server.methods.profileCache.drop = sinon.spy(function (uid) {}); }); it('invalidate cache', function (done) { diff --git a/test/hpkp.js b/test/hpkp.js index 2c7fe87..45adf46 100644 --- a/test/hpkp.js +++ b/test/hpkp.js @@ -6,6 +6,7 @@ const assert = require('insist'); /*global describe,it,beforeEach*/ + function clearRequireCache() { // Delete require cache so that correct configuration values get injected when // recreating server @@ -34,39 +35,36 @@ describe('HPKP', function () { clearRequireCache(); }); - it('should set report header', function (done) { + it('should set report header', async () => { process.env.HPKP_REPORT_ONLY = false; - Server = require('../lib/server').create(); - Server.inject(requestOptions).then(function (res) { + Server = await require('../lib/server').create(); + await Server.inject(requestOptions).then(function (res) { assert.equal(res.statusCode, 200); assert.equal(res.headers['public-key-pins'], 'pin-sha256="orlando="; pin-sha256="magic="; max-age=1; includeSubdomains'); - done(); - }).catch(done); + }); }); - it('should set report-only header', function (done) { + it('should set report-only header', async () => { process.env.HPKP_REPORT_ONLY = true; - Server = require('../lib/server').create(); - Server.inject(requestOptions).then(function (res) { + Server = await require('../lib/server').create(); + await Server.inject(requestOptions).then(function (res) { assert.equal(res.statusCode, 200); assert.equal(res.headers['public-key-pins-report-only'], 'pin-sha256="orlando="; pin-sha256="magic="; max-age=1; includeSubdomains'); - done(); - }).catch(done); + }); }); }); describe('disabled', function () { - it('should set no header', function (done) { + it('should set no header', async () => { process.env.HPKP_ENABLE = false; clearRequireCache(); - Server = require('../lib/server').create(); - Server.inject(requestOptions).then(function (res) { + Server = await require('../lib/server').create(); + await Server.inject(requestOptions).then(function (res) { assert.equal(res.statusCode, 200); assert.equal(res.headers['public-key-pins'], undefined); assert.equal(res.headers['public-key-pins-report-only'], undefined); - done(); - }).catch(done); + }); }); }); }); diff --git a/test/lib/server.js b/test/lib/server.js index 2f11d7f..6a51d3c 100644 --- a/test/lib/server.js +++ b/test/lib/server.js @@ -3,15 +3,15 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const version = require('../../lib/config').get('api.version'); -const P = require('../../lib/promise'); -const Server = require('../../lib/server'); +//const P = require('../../lib/promise'); -var server = Server.create(); +var server; +var api = {}; -function request(options) { - var deferred = P.defer(); - server.inject(options, deferred.resolve.bind(deferred)); - return deferred.promise; +async function create() { + server = await require('../../lib/server').create(); + await expose(); + return server; } function opts(options) { @@ -21,22 +21,31 @@ function opts(options) { return options; } -['GET', 'POST', 'PUT', 'DELETE'].forEach(function(method) { - exports[method.toLowerCase()] = exports[method] = function(options) { - options = opts(options); - options.method = method; - return request(options); - }; -}); +function request(options) { + return new Promise((resolve) => { + server.inject(options).then((res) => { + return resolve(res); + }); + }); +} -var api = {}; -Object.keys(exports).forEach(function(key) { - api[key] = function api(options) { - options = opts(options); - options.url = '/v' + version + options.url; - return exports[key](options); - }; -}); +async function expose() { + ['GET', 'POST', 'PUT', 'DELETE'].forEach(function (method) { + exports[method.toLowerCase()] = exports[method] = async function (options) { + options = opts(options); + options.method = method; + return request(options); + }; + }); + + Object.keys(exports).forEach(function(key) { + api[key] = function api(options) { + options = opts(options); + options.url = '/v' + version + options.url; + return exports[key](options); + }; + }); +} exports.api = api; -exports.server = server; +exports.server = create; diff --git a/test/server.js b/test/server.js index dccdfcd..74c4e51 100644 --- a/test/server.js +++ b/test/server.js @@ -11,6 +11,10 @@ const db = require('../lib/db'); /*global describe,it*/ +beforeEach(function () { + return Server.server(); +}); + describe('server', function() { function checkVersionAndHeaders(path) { return function(done) { @@ -29,7 +33,7 @@ describe('server', function() { Object.keys(res.headers).forEach(function(header) { assert.ok(! other[header.toLowerCase()]); }); - }).done(done, done); + }); }; }