diff --git a/bin/key_server.js b/bin/key_server.js index dd5ceea8..405952cd 100644 --- a/bin/key_server.js +++ b/bin/key_server.js @@ -7,6 +7,8 @@ var jwtool = require('fxa-jwtool') function main() { var log = require('../lib/log')(config.log.level) + var metricsContext = require('../lib/metrics/context')(log, config) + log.setMetricsContext(metricsContext) process.stdout.write(JSON.stringify({ event: 'config', @@ -87,7 +89,8 @@ function main() { mailer, Password, config, - customs + customs, + metricsContext ) server = Server.create(log, error, config, routes, db) diff --git a/config/index.js b/config/index.js index 0aac98d6..fefbfa85 100644 --- a/config/index.js +++ b/config/index.js @@ -28,6 +28,25 @@ var conf = convict({ env: 'LOG_FORMAT' } }, + memcached: { + address: { + doc: 'Address:port of the memcached server (or `none` to disable memcached)', + default: '127.0.0.1:11211', + env: 'MEMCACHE_METRICS_CONTEXT_ADDRESS' + }, + idle: { + doc: 'Idle timeout for memcached connections (milliseconds)', + format: Number, + default: 30000, + env: 'MEMCACHE_METRICS_CONTEXT_IDLE' + }, + lifetime: { + doc: 'Lifetime for memcached values (seconds)', + format: 'nat', + default: 1800, + env: 'MEMCACHE_METRICS_CONTEXT_LIFETIME' + } + }, publicUrl: { format: 'url', default: 'http://127.0.0.1:9000', diff --git a/lib/log.js b/lib/log.js index d7cb6207..59064f2d 100644 --- a/lib/log.js +++ b/lib/log.js @@ -5,9 +5,9 @@ var EventEmitter = require('events').EventEmitter var util = require('util') var mozlog = require('mozlog') - var config = require('../config') var logConfig = config.get('log') +var P = require('./promise') var StatsDCollector = require('./metrics/statsd') function unbuffer(object) { @@ -36,10 +36,13 @@ function Lug(options) { this.statsd = new StatsDCollector(this.logger) this.statsd.init() - this.metricsContext = require('./metrics/context')(this, config.getProperties()) } util.inherits(Lug, EventEmitter) +Lug.prototype.setMetricsContext = function (metricsContext) { + this.metricsContext = metricsContext +} + Lug.prototype.trace = function (data) { this.logger.debug(data.op, data) } @@ -74,32 +77,43 @@ Lug.prototype.begin = function (op, request) { } Lug.prototype.event = function (name, request, data) { - var e = { - event: name, - data: unbuffer(data) - } - e.data.metricsContext = this.metricsContext.add({}, - request.payload.metricsContext, request.headers.dnt === '1') - this.stdout.write(JSON.stringify(e) + '\n') + var self = this + return this.metricsContext.gather({}, request, name) + .then( + function (metricsContextData) { + var e = { + event: name, + data: unbuffer(data) + } + e.data.metricsContext = metricsContextData + self.stdout.write(JSON.stringify(e) + '\n') + } + ) } Lug.prototype.activityEvent = function (event, request, data) { if (! data || ! data.uid) { - return this.error({ op: 'log.activityEvent', data: data }) + this.error({ op: 'log.activityEvent', data: data }) + return P.resolve() } - var info = this.metricsContext.add({ + var self = this + + return this.metricsContext.gather({ event: event, userAgent: request.headers['user-agent'] - }, request.payload.metricsContext, request.headers.dnt === '1') - optionallySetService(info, request) + }, request, event).then( + function (info) { + optionallySetService(info, request) - Object.keys(data).forEach(function (key) { - info[key] = data[key] - }) + Object.keys(data).forEach(function (key) { + info[key] = data[key] + }) - this.logger.info('activityEvent', info) - this.statsd.write(info) + self.logger.info('activityEvent', info) + self.statsd.write(info) + } + ) } function optionallySetService (data, request) { diff --git a/lib/metrics/context.js b/lib/metrics/context.js index c9f5f503..ae9f48c6 100644 --- a/lib/metrics/context.js +++ b/lib/metrics/context.js @@ -8,6 +8,9 @@ var crypto = require('crypto') var isA = require('joi') var bufferEqualConstantTime = require('buffer-equal-constant-time') var HEX = require('../routes/validators').HEX_STRING +var P = require('../promise') +var Memcached = require('memcached') +P.promisifyAll(Memcached.prototype) var FLOW_ID_LENGTH = 64 @@ -25,36 +28,157 @@ var SCHEMA = isA.object({ utmTerm: isA.string().optional() }).and('flowId', 'flowBeginTime').optional() +var NOP = function () { + return P.resolve() +} + +var NULL_MEMCACHED = { + delAsync: NOP, + getAsync: NOP, + setAsync: NOP +} + module.exports = function (log, config) { + var _memcached return { schema: SCHEMA, - add: add, + stash: stash, + gather: gather, validate: validate } - function add(data, metadata, doNotTrack) { - if (metadata) { - data.time = Date.now() - data.flow_id = metadata.flowId - data.flow_time = calculateFlowTime(data.time, metadata.flowBeginTime) - data.context = metadata.context - data.entrypoint = metadata.entrypoint - data.migration = metadata.migration - data.service = metadata.service - - if (! doNotTrack) { - data.utm_campaign = metadata.utmCampaign - data.utm_content = metadata.utmContent - data.utm_medium = metadata.utmMedium - data.utm_source = metadata.utmSource - data.utm_term = metadata.utmTerm - } + /** + * Stashes metrics context metadata using a key derived from a token + * and an event. Asynchronous, returns a promise. + * + * @param token token to stash the metadata against + * @param events array of event names that constitute a flow + * @param metadata metrics context metadata + */ + function stash (token, events, metadata) { + if (! metadata) { + return P.resolve() } - return data + if (events && typeof events === 'string') { + events = [ events ] + } + + if (! token || ! Array.isArray(events)) { + log.error({ + op: 'metricsContext.stash', + err: new Error('Invalid argument'), + token: token, + events: events + }) + return P.resolve() + } + + var memcached = getMemcached() + + return P.all(events.map(function (event) { + return memcached.setAsync(getKey(token, event), metadata, config.memcached.lifetime) + .catch(function (err) { + log.error({ op: 'metricsContext.stash', err: err }) + }) + })) } + function getMemcached () { + if (_memcached) { + return _memcached + } + + try { + if (config.memcached.address !== 'none') { + _memcached = new Memcached(config.memcached.address, { + timeout: 500, + retries: 1, + retry: 1000, + reconnect: 1000, + idle: config.memcached.idle, + namespace: 'fxa-metrics~' + }) + + return _memcached + } + } catch (err) { + log.error({ op: 'metricsContext.getMemcached', err: err }) + } + + return NULL_MEMCACHED + } + + /** + * Gathers metrics context metadata onto data, using either metadata + * passed in from a request or previously-stashed metadata for a + * token. Asynchronous, returns a promise that resolves to data, + * with metrics context metadata copied to it. + * + * @param data target object + * @param request request object + * @param event event name + */ + function gather (data, request, event) { + var metadata = request.payload && request.payload.metricsContext + var token = request.auth && request.auth.credentials + var doNotTrack = request.headers && request.headers.dnt === '1' + var memcached = getMemcached() + var key = getKey(token, event) + + return P.resolve() + .then(function () { + if (metadata) { + return metadata + } + + if (key) { + return memcached.getAsync(key) + } + }) + .catch(function (err) { + log.error({ op: 'memcached.get', err: err }) + }) + .then(function (metadata) { + if (metadata) { + data.time = Date.now() + data.flow_id = metadata.flowId + data.flow_time = calculateFlowTime(data.time, metadata.flowBeginTime) + data.context = metadata.context + data.entrypoint = metadata.entrypoint + data.migration = metadata.migration + data.service = metadata.service + + if (! doNotTrack) { + data.utm_campaign = metadata.utmCampaign + data.utm_content = metadata.utmContent + data.utm_medium = metadata.utmMedium + data.utm_source = metadata.utmSource + data.utm_term = metadata.utmTerm + } + } + }) + .then(function () { + if (key) { + return memcached.delAsync(key) + } + }) + .catch(function (err) { + log.error({ op: 'memcached.del', err: err }) + }) + .then(function () { + return data + }) + } + + /** + * Checks whether a request's flowId and flowBeginTime are valid. + * Returns a boolean, `true` if the request is valid, `false` if + * it's invalid. + * + * @param request object + */ function validate(request) { var metadata = request.payload.metricsContext @@ -119,6 +243,12 @@ module.exports = function (log, config) { } } +function getKey (token, event) { + if (token && event) { + return [ token.uid.toString('hex'), token.id, event ].join(':') + } +} + function calculateFlowTime (time, flowBeginTime) { if (time <= flowBeginTime) { return 0 diff --git a/lib/routes/account.js b/lib/routes/account.js index 05b02e39..7bd515ef 100644 --- a/lib/routes/account.js +++ b/lib/routes/account.js @@ -177,20 +177,26 @@ module.exports = function ( function (result) { account = result - log.activityEvent('account.created', request, { + return log.activityEvent('account.created', request, { uid: account.uid.toString('hex') }) - + } + ) + .then( + function () { if (account.emailVerified) { - log.event('verified', request, { + return log.event('verified', request, { email: account.email, uid: account.uid, locale: account.locale }) } - + } + ) + .then( + function () { if (service === 'sync') { - log.event('login', request, { + return log.event('login', request, { service: 'sync', uid: account.uid, email: account.email, @@ -223,6 +229,20 @@ module.exports = function ( .then( function (result) { sessionToken = result + return metricsContext.stash(sessionToken, [ + 'device.created', + 'account.signed' + ], form.metricsContext) + } + ) + .then( + function () { + // There is no session token when we emit account.verified + // so stash the data against a synthesized "token" instead. + return metricsContext.stash({ + uid: account.uid, + id: account.emailCode.toString('hex') + }, 'account.verified', form.metricsContext) } ) } @@ -270,8 +290,9 @@ module.exports = function ( } ) .then( - function (keyFetchTokenData) { - keyFetchToken = keyFetchTokenData.data.toString('hex') + function (result) { + keyFetchToken = result + return metricsContext.stash(keyFetchToken, 'account.keyfetch', form.metricsContext) } ) } @@ -285,7 +306,7 @@ module.exports = function ( } if (keyFetchToken) { - response.keyFetchToken = keyFetchToken + response.keyFetchToken = keyFetchToken.data.toString('hex') } return P.resolve(response) @@ -380,6 +401,10 @@ module.exports = function ( if (! match) { throw error.incorrectPassword(emailRecord.email, email) } + + return log.activityEvent('account.login', request, { + uid: emailRecord.uid.toString('hex') + }) } ) }, @@ -416,10 +441,6 @@ module.exports = function ( } function createSessionToken () { - log.activityEvent('account.login', request, { - uid: emailRecord.uid.toString('hex') - }) - var sessionTokenOptions = { uid: emailRecord.uid, email: emailRecord.email, @@ -433,6 +454,10 @@ module.exports = function ( .then( function (result) { sessionToken = result + return metricsContext.stash(sessionToken, [ + 'device.created', + 'account.signed' + ], form.metricsContext) } ) } @@ -457,6 +482,7 @@ module.exports = function ( .then( function (result) { keyFetchToken = result + return metricsContext.stash(keyFetchToken, 'account.keyfetch', form.metricsContext) } ) } @@ -466,7 +492,7 @@ module.exports = function ( function emitSyncLoginEvent () { if (service === 'sync' && request.payload.reason === 'signin') { - log.event('login', request, { + return log.event('login', request, { service: 'sync', uid: emailRecord.uid, email: emailRecord.email, @@ -833,6 +859,13 @@ module.exports = function ( return reply(error.unverifiedAccount()) } db.deleteKeyFetchToken(keyFetchToken) + .then( + function () { + return log.activityEvent('account.keyfetch', request, { + uid: keyFetchToken.uid.toString('hex') + }) + } + ) .then( function () { return { @@ -887,6 +920,7 @@ module.exports = function ( log.begin('Account.device', request) var payload = request.payload var sessionToken = request.auth.credentials + if (payload.id) { // Don't write out the update if nothing has actually changed. if (isSpuriousUpdate(payload, sessionToken)) { @@ -899,21 +933,14 @@ module.exports = function ( throw error.featureNotEnabled() } } + if (payload.pushCallback && (!payload.pushPublicKey || !payload.pushAuthKey)) { payload.pushPublicKey = '' payload.pushAuthKey = '' } - var operation = payload.id ? 'updateDevice' : 'createDevice' - db[operation](sessionToken.uid, sessionToken.tokenId, payload).then( + + upsertDevice().then( function (device) { - if (operation === 'createDevice') { - log.event('device:create', request, { - uid: sessionToken.uid, - id: device.id, - type: device.type, - timestamp: device.createdAt - }) - } reply(butil.unbuffer(device)) push.notifyDeviceConnected(sessionToken.uid, device.name, device.id.toString('hex')) }, @@ -948,6 +975,44 @@ module.exports = function ( return spurious } + function upsertDevice () { + var operation, event, result + if (payload.id) { + operation = 'updateDevice' + event = 'device.updated' + } else { + operation = 'createDevice' + event = 'device.created' + } + + return db[operation](sessionToken.uid, sessionToken.tokenId, payload) + .then( + function (res) { + result = res + return log.activityEvent(event, request, { + uid: sessionToken.uid.toString('hex'), + device_id: result.id.toString('hex') + }) + } + ) + .then( + function () { + if (operation === 'createDevice') { + return log.event('device:create', request, { + uid: sessionToken.uid, + id: result.id, + type: result.type, + timestamp: result.createdAt + }) + } + } + ) + .then( + function () { + return result + } + ) + } } }, { @@ -998,7 +1063,8 @@ module.exports = function ( }, validate: { payload: { - id: isA.string().length(32).regex(HEX_STRING).required() + id: isA.string().length(32).regex(HEX_STRING).required(), + metricsContext: metricsContext.schema } }, response: { @@ -1010,21 +1076,37 @@ module.exports = function ( var sessionToken = request.auth.credentials var uid = sessionToken.uid var id = request.payload.id - push.notifyDeviceDisconnected(uid, id).then(deleteDbDevice, deleteDbDevice) + var result - function deleteDbDevice() { - db.deleteDevice(uid, id).then( - function (result) { - log.event('device:delete', request, { + return push.notifyDeviceDisconnected(uid, id) + .catch(function () {}) + .then( + function () { + return db.deleteDevice(uid, id) + } + ) + .then( + function (res) { + result = res + return log.activityEvent('device.deleted', request, { + uid: uid.toString('hex'), + device_id: id + }) + } + ) + .then( + function () { + return log.event('device:delete', request, { uid: uid, id: id, timestamp: Date.now() }) - reply(result) - }, - reply + } ) - } + .then(function () { + return result + }) + .then(reply, reply) } }, { @@ -1173,7 +1255,8 @@ module.exports = function ( uid: isA.string().max(32).regex(HEX_STRING).required(), code: isA.string().min(32).max(32).regex(HEX_STRING).required(), service: isA.string().max(16).alphanum().optional(), - reminder: isA.string().max(32).alphanum().optional() + reminder: isA.string().max(32).alphanum().optional(), + metricsContext: metricsContext.schema } } }, @@ -1222,28 +1305,50 @@ module.exports = function ( return db.verifyEmail(account) .then(function () { log.timing('account.verified', Date.now() - account.createdAt) - log.event('verified', request, { + log.increment('account.verified') + return log.event('verified', request, { email: account.email, uid: account.uid, locale: account.locale }) - log.increment('account.verified') - + }) + .then(function () { + // Because we have no session token on this endpoint, + // the metrics context metadata was stashed against a + // synthesized token for the benefit of this event. + // Hence we're passing in a synthesized request object + // rather than the real thing. + return log.activityEvent('account.verified', { + auth: { + credentials: { + uid: uid, + id: request.payload.code + } + }, + headers: request.headers, + payload: request.payload, + query: request.query + }, { + uid: account.uid.toString('hex') + }) + }) + .then(function () { if (reminder === 'first' || reminder === 'second') { // if verified using a known reminder var reminderOp = 'account.verified_reminder.' + reminder log.increment(reminderOp) - log.activityEvent('account.reminder', request, { - uid: account.uid.toString('hex') - }) // log to the mailer namespace that account was verified via a reminder log.info({ op: 'mailer.send', name: reminderOp }) + return log.activityEvent('account.reminder', request, { + uid: account.uid.toString('hex') + }) } - + }) + .then(function () { // send a push notification to all devices that the account changed push.notifyUpdate(uid, 'accountVerify') // remove verification reminders @@ -1440,13 +1545,21 @@ module.exports = function ( .then( function (accountData) { account = accountData - log.activityEvent('account.reset', request, { + return log.activityEvent('account.reset', request, { uid: account.uid.toString('hex') }) - log.event('reset', request, { + } + ) + .then( + function () { + return log.event('reset', request, { uid: account.uid.toString('hex') + '@' + config.domain, generation: account.verifierSetAt }) + } + ) + .then( + function () { return customs.reset(account.email) } ) @@ -1478,6 +1591,10 @@ module.exports = function ( .then( function (result) { sessionToken = result + return metricsContext.stash(sessionToken, [ + 'device.created', + 'account.signed' + ], request.payload.metricsContext) } ) } @@ -1499,6 +1616,7 @@ module.exports = function ( .then( function (result) { keyFetchToken = result + return metricsContext.stash(keyFetchToken, 'account.keyfetch', request.payload.metricsContext) } ) } @@ -1563,9 +1681,13 @@ module.exports = function ( ) .then( function () { - log.event('delete', request, { + return log.event('delete', request, { uid: emailRecord.uid.toString('hex') + '@' + config.domain }) + } + ) + .then( + function () { return {} } ) diff --git a/lib/routes/index.js b/lib/routes/index.js index d30c8317..9225fb1b 100644 --- a/lib/routes/index.js +++ b/lib/routes/index.js @@ -18,17 +18,14 @@ module.exports = function ( mailer, Password, config, - customs + customs, + metricsContext ) { var isPreVerified = require('../preverifier')(error, config) var defaults = require('./defaults')(log, P, db, error) var idp = require('./idp')(log, serverPublicKeys) var checkPassword = require('./utils/password_check')(log, config, Password, customs, db) var push = require('../push')(log, db) - var metricsContext = log.metricsContext - if (!metricsContext) { - metricsContext = require('../metrics/context')(log, config.getProperties()) - } var account = require('./account')( log, crypto, @@ -59,7 +56,7 @@ module.exports = function ( checkPassword, push ) - var session = require('./session')(log, isA, error, db) + var session = require('./session')(log, isA, error, db, metricsContext) var sign = require('./sign')(log, isA, error, signer, db, config.domain, metricsContext) var util = require('./util')( log, diff --git a/lib/routes/session.js b/lib/routes/session.js index 91b5f4fd..1e10ea6b 100644 --- a/lib/routes/session.js +++ b/lib/routes/session.js @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -module.exports = function (log, isA, error, db) { +module.exports = function (log, isA, error, db, metricsContext) { var routes = [ { @@ -17,7 +17,7 @@ module.exports = function (log, isA, error, db) { log.begin('Session.destroy', request) var sessionToken = request.auth.credentials db.deleteSessionToken(sessionToken) - .done( + .then( function () { reply({}) }, diff --git a/lib/routes/sign.js b/lib/routes/sign.js index f2ede90e..10396bf6 100644 --- a/lib/routes/sign.js +++ b/lib/routes/sign.js @@ -90,6 +90,7 @@ module.exports = function (log, isA, error, signer, db, domain, metricsContext) } var uid = sessionToken.uid.toString('hex') var deviceId = sessionToken.deviceId ? sessionToken.deviceId.toString('hex') : null + var certResult return signer.sign( { @@ -105,8 +106,9 @@ module.exports = function (log, isA, error, signer, db, domain, metricsContext) } ) .then( - function(certResult) { - log.activityEvent( + function(result) { + certResult = result + return log.activityEvent( 'account.signed', request, { @@ -115,6 +117,10 @@ module.exports = function (log, isA, error, signer, db, domain, metricsContext) device_id: deviceId } ) + } + ) + .then( + function () { reply(certResult) }, reply diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index c75e2a39..36d88a91 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -352,7 +352,7 @@ }, "buffer-equal-constant-time": { "version": "1.0.1", - "from": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "from": "buffer-equal-constant-time@1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" }, "commander": { @@ -460,9 +460,9 @@ "resolved": "https://registry.npmjs.org/eslint-config-fxa/-/eslint-config-fxa-1.6.0.tgz" }, "fxa-auth-db-mysql": { - "version": "0.62.0", + "version": "0.63.0", "from": "git+https://github.com/mozilla/fxa-auth-db-mysql.git#master", - "resolved": "git+https://github.com/mozilla/fxa-auth-db-mysql.git#06b8db63eabf287aee761338eb54655758f37e4e", + "resolved": "git+https://github.com/mozilla/fxa-auth-db-mysql.git#b696e9d6dbebc329e7ff2d979cd01c9631deb567", "dependencies": { "bluebird": { "version": "2.1.3", @@ -713,9 +713,9 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz" }, "tunnel-agent": { - "version": "0.4.2", - "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz" + "version": "0.4.3", + "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" }, "tough-cookie": { "version": "2.2.2", @@ -801,9 +801,9 @@ } }, "bunyan": { - "version": "1.8.0", - "from": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.0.tgz", - "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.0.tgz", + "version": "1.8.1", + "from": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.1.tgz", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.1.tgz", "dependencies": { "mv": { "version": "2.1.1", @@ -838,14 +838,14 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", "dependencies": { "inflight": { - "version": "1.0.4", - "from": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", + "version": "1.0.5", + "from": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", "dependencies": { "wrappy": { - "version": "1.0.1", - "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + "version": "1.0.2", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" } } }, @@ -855,19 +855,19 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, "minimatch": { - "version": "3.0.0", - "from": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", + "version": "3.0.2", + "from": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", "dependencies": { "brace-expansion": { - "version": "1.1.3", - "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", + "version": "1.1.5", + "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", "dependencies": { "balanced-match": { - "version": "0.3.0", - "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz" + "version": "0.4.1", + "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" }, "concat-map": { "version": "0.0.1", @@ -912,9 +912,9 @@ "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-0.0.6.tgz" }, "csv-parse": { - "version": "1.0.4", - "from": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.0.4.tgz", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.0.4.tgz" + "version": "1.1.1", + "from": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.1.1.tgz" }, "stream-transform": { "version": "0.1.1", @@ -986,9 +986,9 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "dependencies": { "wrappy": { - "version": "1.0.1", - "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + "version": "1.0.2", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" } } }, @@ -1008,9 +1008,9 @@ "resolved": "https://registry.npmjs.org/spdy/-/spdy-1.32.5.tgz" }, "tunnel-agent": { - "version": "0.4.2", - "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz" + "version": "0.4.3", + "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" }, "vasync": { "version": "1.6.3", @@ -1054,9 +1054,9 @@ "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz", "dependencies": { "nan": { - "version": "2.2.1", - "from": "https://registry.npmjs.org/nan/-/nan-2.2.1.tgz", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.2.1.tgz" + "version": "2.3.5", + "from": "https://registry.npmjs.org/nan/-/nan-2.3.5.tgz", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.5.tgz" } } } @@ -1065,33 +1065,33 @@ } }, "fxa-auth-mailer": { - "version": "1.0.8", + "version": "1.63.0", "from": "git+https://github.com/mozilla/fxa-auth-mailer.git#master", "resolved": "git+https://github.com/mozilla/fxa-auth-mailer.git#1997b3f0270b6bb97c744b30f4424a0db9a3c151", "dependencies": { "bluebird": { "version": "2.9.34", - "from": "bluebird@2.9.34", + "from": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.34.tgz", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.34.tgz" }, "convict": { "version": "1.0.2", - "from": "convict@1.0.2", + "from": "https://registry.npmjs.org/convict/-/convict-1.0.2.tgz", "resolved": "https://registry.npmjs.org/convict/-/convict-1.0.2.tgz", "dependencies": { "cjson": { "version": "0.3.2", - "from": "cjson@0.3.2", + "from": "https://registry.npmjs.org/cjson/-/cjson-0.3.2.tgz", "resolved": "https://registry.npmjs.org/cjson/-/cjson-0.3.2.tgz", "dependencies": { "json-parse-helpfulerror": { "version": "1.0.3", - "from": "json-parse-helpfulerror@>=1.0.3 <2.0.0", + "from": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", "dependencies": { "jju": { "version": "1.3.0", - "from": "jju@>=1.1.0 <2.0.0", + "from": "https://registry.npmjs.org/jju/-/jju-1.3.0.tgz", "resolved": "https://registry.npmjs.org/jju/-/jju-1.3.0.tgz" } } @@ -1100,49 +1100,49 @@ }, "depd": { "version": "1.1.0", - "from": "depd@1.1.0", + "from": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz" }, "moment": { "version": "2.10.6", - "from": "moment@2.10.6", + "from": "https://registry.npmjs.org/moment/-/moment-2.10.6.tgz", "resolved": "https://registry.npmjs.org/moment/-/moment-2.10.6.tgz" }, "optimist": { "version": "0.6.1", - "from": "optimist@0.6.1", + "from": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "dependencies": { "wordwrap": { "version": "0.0.3", - "from": "wordwrap@>=0.0.2 <0.1.0", + "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" }, "minimist": { "version": "0.0.10", - "from": "minimist@>=0.0.1 <0.1.0", + "from": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz" } } }, "validator": { "version": "4.0.5", - "from": "validator@4.0.5", + "from": "https://registry.npmjs.org/validator/-/validator-4.0.5.tgz", "resolved": "https://registry.npmjs.org/validator/-/validator-4.0.5.tgz" }, "varify": { "version": "0.1.1", - "from": "varify@0.1.1", + "from": "https://registry.npmjs.org/varify/-/varify-0.1.1.tgz", "resolved": "https://registry.npmjs.org/varify/-/varify-0.1.1.tgz", "dependencies": { "redeyed": { "version": "0.4.4", - "from": "redeyed@>=0.4.2 <0.5.0", + "from": "https://registry.npmjs.org/redeyed/-/redeyed-0.4.4.tgz", "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-0.4.4.tgz", "dependencies": { "esprima": { "version": "1.0.4", - "from": "esprima@>=1.0.4 <1.1.0", + "from": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz" } } @@ -1153,106 +1153,106 @@ }, "fxa-content-server-l10n": { "version": "0.0.0", - "from": "git://github.com/mozilla/fxa-content-server-l10n.git", - "resolved": "git://github.com/mozilla/fxa-content-server-l10n.git#dc7d3c5136bcec6658bf6d3633d1fd6d7bf25965" + "from": "git://github.com/mozilla/fxa-content-server-l10n.git#347e679070c65811ed7183ccde52c48768a8cfc5", + "resolved": "git://github.com/mozilla/fxa-content-server-l10n.git#347e679070c65811ed7183ccde52c48768a8cfc5" }, "grunt-nunjucks-2-html": { "version": "0.3.4", - "from": "vitkarpov/grunt-nunjucks-2-html#1900f91a756b2eaf900b20", + "from": "git://github.com/vitkarpov/grunt-nunjucks-2-html.git#1900f91a756b2eaf900b20ca7a28b10267ca55ba", "resolved": "git://github.com/vitkarpov/grunt-nunjucks-2-html.git#1900f91a756b2eaf900b20ca7a28b10267ca55ba", "dependencies": { "async": { "version": "1.5.2", - "from": "async@>=1.4.2 <2.0.0", + "from": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz" }, "nunjucks": { "version": "2.4.2", - "from": "nunjucks@>=2.1.0 <3.0.0", + "from": "https://registry.npmjs.org/nunjucks/-/nunjucks-2.4.2.tgz", "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-2.4.2.tgz", "dependencies": { "asap": { - "version": "2.0.3", - "from": "asap@>=2.0.3 <3.0.0", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.3.tgz" + "version": "2.0.4", + "from": "https://registry.npmjs.org/asap/-/asap-2.0.4.tgz", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.4.tgz" }, "chokidar": { - "version": "1.4.3", - "from": "chokidar@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.4.3.tgz", + "version": "1.5.2", + "from": "https://registry.npmjs.org/chokidar/-/chokidar-1.5.2.tgz", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.5.2.tgz", "dependencies": { "anymatch": { "version": "1.3.0", - "from": "anymatch@>=1.3.0 <2.0.0", + "from": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", "dependencies": { "arrify": { "version": "1.0.1", - "from": "arrify@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" }, "micromatch": { - "version": "2.3.8", - "from": "micromatch@>=2.1.5 <3.0.0", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.8.tgz", + "version": "2.3.10", + "from": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.10.tgz", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.10.tgz", "dependencies": { "arr-diff": { "version": "2.0.0", - "from": "arr-diff@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "dependencies": { "arr-flatten": { "version": "1.0.1", - "from": "arr-flatten@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz" } } }, "array-unique": { "version": "0.2.1", - "from": "array-unique@>=0.2.1 <0.3.0", + "from": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz" }, "braces": { - "version": "1.8.4", - "from": "braces@>=1.8.2 <2.0.0", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.4.tgz", + "version": "1.8.5", + "from": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "dependencies": { "expand-range": { - "version": "1.8.1", - "from": "expand-range@>=1.8.1 <2.0.0", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.1.tgz", + "version": "1.8.2", + "from": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "dependencies": { "fill-range": { "version": "2.2.3", - "from": "fill-range@>=2.1.0 <3.0.0", + "from": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", "dependencies": { "is-number": { "version": "2.1.0", - "from": "is-number@>=2.1.0 <3.0.0", + "from": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz" }, "isobject": { "version": "2.1.0", - "from": "isobject@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "dependencies": { "isarray": { "version": "1.0.0", - "from": "isarray@1.0.0", + "from": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" } } }, "randomatic": { "version": "1.1.5", - "from": "randomatic@>=1.1.3 <2.0.0", + "from": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.5.tgz", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.5.tgz" }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", + "from": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" } } @@ -1261,114 +1261,114 @@ }, "preserve": { "version": "0.2.0", - "from": "preserve@>=0.2.0 <0.3.0", + "from": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz" }, "repeat-element": { "version": "1.1.2", - "from": "repeat-element@>=1.1.2 <2.0.0", + "from": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz" } } }, "expand-brackets": { "version": "0.1.5", - "from": "expand-brackets@>=0.1.4 <0.2.0", + "from": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "dependencies": { "is-posix-bracket": { "version": "0.1.1", - "from": "is-posix-bracket@>=0.1.0 <0.2.0", + "from": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz" } } }, "extglob": { "version": "0.3.2", - "from": "extglob@>=0.3.1 <0.4.0", + "from": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz" }, "filename-regex": { "version": "2.0.0", - "from": "filename-regex@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz" }, "is-extglob": { "version": "1.0.0", - "from": "is-extglob@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz" }, "kind-of": { "version": "3.0.3", - "from": "kind-of@>=3.0.2 <4.0.0", + "from": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", "dependencies": { "is-buffer": { "version": "1.1.3", - "from": "is-buffer@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" } } }, "normalize-path": { "version": "2.0.1", - "from": "normalize-path@>=2.0.1 <3.0.0", + "from": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz" }, "object.omit": { "version": "2.0.0", - "from": "object.omit@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.0.tgz", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.0.tgz", "dependencies": { "for-own": { "version": "0.1.4", - "from": "for-own@>=0.1.3 <0.2.0", + "from": "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz", "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz", "dependencies": { "for-in": { "version": "0.1.5", - "from": "for-in@>=0.1.5 <0.2.0", + "from": "https://registry.npmjs.org/for-in/-/for-in-0.1.5.tgz", "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.5.tgz" } } }, "is-extendable": { "version": "0.1.1", - "from": "is-extendable@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" } } }, "parse-glob": { "version": "3.0.4", - "from": "parse-glob@>=3.0.4 <4.0.0", + "from": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "dependencies": { "glob-base": { "version": "0.3.0", - "from": "glob-base@>=0.3.0 <0.4.0", + "from": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz" }, "is-dotfile": { "version": "1.0.2", - "from": "is-dotfile@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz" } } }, "regex-cache": { "version": "0.4.3", - "from": "regex-cache@>=0.4.2 <0.5.0", + "from": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", "dependencies": { "is-equal-shallow": { "version": "0.1.3", - "from": "is-equal-shallow@>=0.1.3 <0.2.0", + "from": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz" }, "is-primitive": { "version": "2.0.0", - "from": "is-primitive@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz" } } @@ -1379,76 +1379,76 @@ }, "async-each": { "version": "1.0.0", - "from": "async-each@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/async-each/-/async-each-1.0.0.tgz", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.0.tgz" }, "glob-parent": { "version": "2.0.0", - "from": "glob-parent@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz" }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.1 <3.0.0", + "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, "is-binary-path": { "version": "1.0.1", - "from": "is-binary-path@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "dependencies": { "binary-extensions": { - "version": "1.4.0", - "from": "binary-extensions@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.4.0.tgz" + "version": "1.4.1", + "from": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.4.1.tgz", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.4.1.tgz" } } }, "is-glob": { "version": "2.0.1", - "from": "is-glob@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "dependencies": { "is-extglob": { "version": "1.0.0", - "from": "is-extglob@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz" } } }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" }, "readdirp": { "version": "2.0.0", - "from": "readdirp@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/readdirp/-/readdirp-2.0.0.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.0.0.tgz", "dependencies": { "graceful-fs": { - "version": "4.1.3", - "from": "graceful-fs@>=4.1.2 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz" + "version": "4.1.4", + "from": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz" }, "minimatch": { "version": "2.0.10", - "from": "minimatch@>=2.0.10 <3.0.0", + "from": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "dependencies": { "brace-expansion": { - "version": "1.1.4", - "from": "brace-expansion@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.4.tgz", + "version": "1.1.5", + "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", "dependencies": { "balanced-match": { "version": "0.4.1", - "from": "balanced-match@>=0.4.1 <0.5.0", + "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", + "from": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" } } @@ -1456,33 +1456,38 @@ } }, "readable-stream": { - "version": "2.1.2", - "from": "readable-stream@>=2.0.2 <3.0.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.2.tgz", + "version": "2.1.4", + "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.4.tgz", "dependencies": { + "buffer-shims": { + "version": "1.0.0", + "from": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz" + }, "core-util-is": { "version": "1.0.2", - "from": "core-util-is@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" }, "isarray": { "version": "1.0.0", - "from": "isarray@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "process-nextick-args": { - "version": "1.0.6", - "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz" + "version": "1.0.7", + "from": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" }, "string_decoder": { "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0", + "from": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" }, "util-deprecate": { "version": "1.0.2", - "from": "util-deprecate@>=1.0.1 <1.1.0", + "from": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" } } @@ -1491,13 +1496,13 @@ }, "fsevents": { "version": "1.0.12", - "from": "fsevents@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.12.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.12.tgz", "dependencies": { "nan": { - "version": "2.3.3", - "from": "nan@>=2.3.0 <3.0.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.3.tgz" + "version": "2.3.5", + "from": "https://registry.npmjs.org/nan/-/nan-2.3.5.tgz", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.5.tgz" }, "node-pre-gyp": { "version": "0.6.25", @@ -1538,16 +1543,16 @@ "from": "are-we-there-yet@~1.1.2", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz" }, - "assert-plus": { - "version": "0.2.0", - "from": "assert-plus@^0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz" - }, "asn1": { "version": "0.2.3", "from": "asn1@>=0.2.3 <0.3.0", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz" }, + "assert-plus": { + "version": "0.2.0", + "from": "assert-plus@^0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz" + }, "async": { "version": "1.5.2", "from": "async@^1.5.2", @@ -1593,16 +1598,16 @@ "from": "commander@^2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz" }, - "core-util-is": { - "version": "1.0.2", - "from": "core-util-is@~1.0.0", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - }, "cryptiles": { "version": "2.0.5", "from": "cryptiles@2.x.x", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz" }, + "core-util-is": { + "version": "1.0.2", + "from": "core-util-is@~1.0.0", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" + }, "debug": { "version": "2.2.0", "from": "debug@~2.2.0", @@ -1638,16 +1643,16 @@ "from": "extend@~3.0.0", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz" }, - "forever-agent": { - "version": "0.6.1", - "from": "forever-agent@~0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" - }, "extsprintf": { "version": "1.0.2", "from": "extsprintf@1.0.2", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz" }, + "forever-agent": { + "version": "0.6.1", + "from": "forever-agent@~0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" + }, "form-data": { "version": "1.0.0-rc4", "from": "form-data@~1.0.0-rc3", @@ -1683,6 +1688,11 @@ "from": "graceful-readlink@>= 1.0.0", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" }, + "har-validator": { + "version": "2.0.6", + "from": "har-validator@~2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz" + }, "has-ansi": { "version": "2.0.0", "from": "has-ansi@^2.0.0", @@ -1693,11 +1703,6 @@ "from": "has-unicode@^2.0.0", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.0.tgz" }, - "har-validator": { - "version": "2.0.6", - "from": "har-validator@~2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz" - }, "hawk": { "version": "3.1.3", "from": "hawk@~3.1.0", @@ -1718,16 +1723,16 @@ "from": "inherits@*", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, - "is-my-json-valid": { - "version": "2.13.1", - "from": "is-my-json-valid@^2.12.4", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz" - }, "ini": { "version": "1.3.4", "from": "ini@~1.3.0", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz" }, + "is-my-json-valid": { + "version": "2.13.1", + "from": "is-my-json-valid@^2.12.4", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz" + }, "is-property": { "version": "1.0.2", "from": "is-property@^1.0.0", @@ -2125,56 +2130,56 @@ }, "yargs": { "version": "3.32.0", - "from": "yargs@>=3.32.0 <4.0.0", + "from": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", "dependencies": { "camelcase": { "version": "2.1.1", - "from": "camelcase@>=2.0.1 <3.0.0", + "from": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz" }, "cliui": { "version": "3.2.0", - "from": "cliui@>=3.0.3 <4.0.0", + "from": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "dependencies": { "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.1 <4.0.0", + "from": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" } } }, "wrap-ansi": { "version": "2.0.0", - "from": "wrap-ansi@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.0.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.0.0.tgz" } } }, "decamelize": { "version": "1.2.0", - "from": "decamelize@>=1.1.1 <2.0.0", + "from": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" }, "os-locale": { "version": "1.4.0", - "from": "os-locale@>=1.4.0 <2.0.0", + "from": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "dependencies": { "lcid": { "version": "1.0.0", - "from": "lcid@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "dependencies": { "invert-kv": { "version": "1.0.0", - "from": "invert-kv@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz" } } @@ -2183,41 +2188,41 @@ }, "string-width": { "version": "1.0.1", - "from": "string-width@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz", "dependencies": { "code-point-at": { "version": "1.0.0", - "from": "code-point-at@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz", "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" } } }, "is-fullwidth-code-point": { "version": "1.0.0", - "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "dependencies": { "number-is-nan": { "version": "1.0.0", - "from": "number-is-nan@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.0.tgz" } } }, "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.0 <4.0.0", + "from": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" } } @@ -2226,12 +2231,12 @@ }, "window-size": { "version": "0.1.4", - "from": "window-size@>=0.1.4 <0.2.0", + "from": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz" }, "y18n": { "version": "3.2.1", - "from": "y18n@>=3.2.0 <4.0.0", + "from": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz" } } @@ -2242,39 +2247,39 @@ }, "handlebars": { "version": "1.3.0", - "from": "handlebars@1.3.0", + "from": "https://registry.npmjs.org/handlebars/-/handlebars-1.3.0.tgz", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-1.3.0.tgz", "dependencies": { "optimist": { "version": "0.3.7", - "from": "optimist@>=0.3.0 <0.4.0", + "from": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", "dependencies": { "wordwrap": { "version": "0.0.3", - "from": "wordwrap@>=0.0.2 <0.1.0", + "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" } } }, "uglify-js": { "version": "2.3.6", - "from": "uglify-js@>=2.3.0 <2.4.0", + "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz", "dependencies": { "async": { "version": "0.2.10", - "from": "async@>=0.2.6 <0.3.0", + "from": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" }, "source-map": { "version": "0.1.43", - "from": "source-map@>=0.1.7 <0.2.0", + "from": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "dependencies": { "amdefine": { "version": "1.0.0", - "from": "amdefine@>=0.0.4", + "from": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" } } @@ -2285,12 +2290,12 @@ }, "i18n-abide": { "version": "0.0.23", - "from": "i18n-abide@0.0.23", + "from": "https://registry.npmjs.org/i18n-abide/-/i18n-abide-0.0.23.tgz", "resolved": "https://registry.npmjs.org/i18n-abide/-/i18n-abide-0.0.23.tgz", "dependencies": { "async": { "version": "0.9.0", - "from": "async@0.9.0", + "from": "https://registry.npmjs.org/async/-/async-0.9.0.tgz", "resolved": "https://registry.npmjs.org/async/-/async-0.9.0.tgz" }, "gobbledygook": { @@ -2300,27 +2305,27 @@ }, "jsxgettext": { "version": "0.7.0", - "from": "jsxgettext@0.7.0", + "from": "https://registry.npmjs.org/jsxgettext/-/jsxgettext-0.7.0.tgz", "resolved": "https://registry.npmjs.org/jsxgettext/-/jsxgettext-0.7.0.tgz", "dependencies": { "acorn": { "version": "0.11.0", - "from": "acorn@>=0.11.0 <0.12.0", + "from": "https://registry.npmjs.org/acorn/-/acorn-0.11.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-0.11.0.tgz" }, "gettext-parser": { - "version": "1.1.2", - "from": "gettext-parser@>=1.1.0 <2.0.0", - "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.1.2.tgz", + "version": "1.2.0", + "from": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.2.0.tgz", "dependencies": { "encoding": { "version": "0.1.12", - "from": "encoding@>=0.1.11 <0.2.0", + "from": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "dependencies": { "iconv-lite": { "version": "0.4.13", - "from": "iconv-lite@>=0.4.13 <0.5.0", + "from": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz" } } @@ -2329,44 +2334,44 @@ }, "commander": { "version": "2.5.0", - "from": "commander@2.5.0", + "from": "https://registry.npmjs.org/commander/-/commander-2.5.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.5.0.tgz" }, "jade": { "version": "1.11.0", - "from": "jade@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", "resolved": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz", "dependencies": { "character-parser": { "version": "1.2.1", - "from": "character-parser@1.2.1", + "from": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz", "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-1.2.1.tgz" }, "clean-css": { - "version": "3.4.12", - "from": "clean-css@>=3.1.9 <4.0.0", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.12.tgz", + "version": "3.4.18", + "from": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.18.tgz", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.18.tgz", "dependencies": { "commander": { "version": "2.8.1", - "from": "commander@>=2.8.0 <2.9.0", + "from": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", "dependencies": { "graceful-readlink": { "version": "1.0.1", - "from": "graceful-readlink@>=1.0.0", + "from": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" } } }, "source-map": { "version": "0.4.4", - "from": "source-map@>=0.4.0 <0.5.0", + "from": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", "dependencies": { "amdefine": { "version": "1.0.0", - "from": "amdefine@>=0.0.4", + "from": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" } } @@ -2375,116 +2380,104 @@ }, "commander": { "version": "2.6.0", - "from": "commander@>=2.6.0 <2.7.0", + "from": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz" }, "constantinople": { "version": "3.0.2", - "from": "constantinople@>=3.0.1 <3.1.0", + "from": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.0.2.tgz", "dependencies": { "acorn": { "version": "2.7.0", - "from": "acorn@>=2.1.0 <3.0.0", + "from": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz" } } }, "jstransformer": { "version": "0.0.2", - "from": "jstransformer@0.0.2", + "from": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz", "dependencies": { "is-promise": { "version": "2.1.0", - "from": "is-promise@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz" }, "promise": { "version": "6.1.0", - "from": "promise@>=6.0.1 <7.0.0", + "from": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", "resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz", "dependencies": { "asap": { "version": "1.0.0", - "from": "asap@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz" } } } } }, - "mkdirp": { - "version": "0.5.1", - "from": "mkdirp@>=0.5.0 <0.6.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "dependencies": { - "minimist": { - "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" - } - } - }, "transformers": { "version": "2.1.0", - "from": "transformers@2.1.0", + "from": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", "resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz", "dependencies": { "promise": { "version": "2.0.0", - "from": "promise@>=2.0.0 <2.1.0", + "from": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", "resolved": "https://registry.npmjs.org/promise/-/promise-2.0.0.tgz", "dependencies": { "is-promise": { "version": "1.0.1", - "from": "is-promise@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz" } } }, "css": { "version": "1.0.8", - "from": "css@>=1.0.8 <1.1.0", + "from": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", "resolved": "https://registry.npmjs.org/css/-/css-1.0.8.tgz", "dependencies": { "css-parse": { "version": "1.0.4", - "from": "css-parse@1.0.4", + "from": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz", "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.0.4.tgz" }, "css-stringify": { "version": "1.0.5", - "from": "css-stringify@1.0.5", + "from": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz", "resolved": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz" } } }, "uglify-js": { "version": "2.2.5", - "from": "uglify-js@>=2.2.5 <2.3.0", + "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.2.5.tgz", "dependencies": { "source-map": { "version": "0.1.43", - "from": "source-map@>=0.1.7 <0.2.0", + "from": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", "dependencies": { "amdefine": { "version": "1.0.0", - "from": "amdefine@>=0.0.4", + "from": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" } } }, "optimist": { "version": "0.3.7", - "from": "optimist@>=0.3.5 <0.4.0", + "from": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", "dependencies": { "wordwrap": { "version": "0.0.3", - "from": "wordwrap@>=0.0.2 <0.1.0", + "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" } } @@ -2494,111 +2487,111 @@ } }, "uglify-js": { - "version": "2.6.2", - "from": "uglify-js@>=2.4.19 <3.0.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.2.tgz", + "version": "2.6.3", + "from": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.3.tgz", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.3.tgz", "dependencies": { "async": { "version": "0.2.10", - "from": "async@>=0.2.6 <0.3.0", + "from": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" }, "source-map": { "version": "0.5.6", - "from": "source-map@>=0.5.1 <0.6.0", + "from": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz" }, "uglify-to-browserify": { "version": "1.0.2", - "from": "uglify-to-browserify@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz" }, "yargs": { "version": "3.10.0", - "from": "yargs@>=3.10.0 <3.11.0", + "from": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", "dependencies": { "camelcase": { "version": "1.2.1", - "from": "camelcase@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz" }, "cliui": { "version": "2.1.0", - "from": "cliui@>=2.1.0 <3.0.0", + "from": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", "dependencies": { "center-align": { "version": "0.1.3", - "from": "center-align@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", "dependencies": { "align-text": { "version": "0.1.4", - "from": "align-text@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "dependencies": { "kind-of": { "version": "3.0.3", - "from": "kind-of@>=3.0.2 <4.0.0", + "from": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", "dependencies": { "is-buffer": { "version": "1.1.3", - "from": "is-buffer@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" } } }, "longest": { "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", + "from": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" } } }, "lazy-cache": { "version": "1.0.4", - "from": "lazy-cache@>=1.0.3 <2.0.0", + "from": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz" } } }, "right-align": { "version": "0.1.3", - "from": "right-align@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "dependencies": { "align-text": { "version": "0.1.4", - "from": "align-text@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", "dependencies": { "kind-of": { "version": "3.0.3", - "from": "kind-of@>=3.0.2 <4.0.0", + "from": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.0.3.tgz", "dependencies": { "is-buffer": { "version": "1.1.3", - "from": "is-buffer@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.3.tgz" } } }, "longest": { "version": "1.0.1", - "from": "longest@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz" }, "repeat-string": { "version": "1.5.4", - "from": "repeat-string@>=1.5.2 <2.0.0", + "from": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.5.4.tgz" } } @@ -2607,19 +2600,19 @@ }, "wordwrap": { "version": "0.0.2", - "from": "wordwrap@0.0.2", + "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz" } } }, "decamelize": { "version": "1.2.0", - "from": "decamelize@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" }, "window-size": { "version": "0.1.0", - "from": "window-size@0.1.0", + "from": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz" } } @@ -2628,27 +2621,27 @@ }, "void-elements": { "version": "2.0.1", - "from": "void-elements@>=2.0.1 <2.1.0", + "from": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz" }, "with": { "version": "4.0.3", - "from": "with@>=4.0.0 <4.1.0", + "from": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", "resolved": "https://registry.npmjs.org/with/-/with-4.0.3.tgz", "dependencies": { "acorn": { "version": "1.2.2", - "from": "acorn@>=1.0.1 <2.0.0", + "from": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-1.2.2.tgz" }, "acorn-globals": { "version": "1.0.9", - "from": "acorn-globals@>=1.0.3 <2.0.0", + "from": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", "dependencies": { "acorn": { "version": "2.7.0", - "from": "acorn@>=2.1.0 <3.0.0", + "from": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz" } } @@ -2659,58 +2652,58 @@ }, "escape-string-regexp": { "version": "1.0.1", - "from": "escape-string-regexp@1.0.1", + "from": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.1.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.1.tgz" } } }, "optimist": { "version": "0.6.1", - "from": "optimist@0.6.1", + "from": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "dependencies": { "wordwrap": { "version": "0.0.3", - "from": "wordwrap@>=0.0.2 <0.1.0", + "from": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" }, "minimist": { "version": "0.0.10", - "from": "minimist@>=0.0.1 <0.1.0", + "from": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz" } } }, "plist": { "version": "1.1.0", - "from": "plist@1.1.0", + "from": "https://registry.npmjs.org/plist/-/plist-1.1.0.tgz", "resolved": "https://registry.npmjs.org/plist/-/plist-1.1.0.tgz", "dependencies": { "base64-js": { "version": "0.0.6", - "from": "base64-js@0.0.6", + "from": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.6.tgz", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.6.tgz" }, "xmlbuilder": { "version": "2.2.1", - "from": "xmlbuilder@2.2.1", + "from": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.2.1.tgz", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.2.1.tgz", "dependencies": { "lodash-node": { "version": "2.4.1", - "from": "lodash-node@>=2.4.1 <2.5.0", + "from": "https://registry.npmjs.org/lodash-node/-/lodash-node-2.4.1.tgz", "resolved": "https://registry.npmjs.org/lodash-node/-/lodash-node-2.4.1.tgz" } } }, "xmldom": { "version": "0.1.22", - "from": "xmldom@>=0.1.0 <0.2.0", + "from": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.22.tgz", "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.22.tgz" }, "util-deprecate": { "version": "1.0.0", - "from": "util-deprecate@1.0.0", + "from": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.0.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.0.tgz" } } @@ -2719,68 +2712,68 @@ }, "jed": { "version": "0.5.4", - "from": "jed@0.5.4", + "from": "https://registry.npmjs.org/jed/-/jed-0.5.4.tgz", "resolved": "https://registry.npmjs.org/jed/-/jed-0.5.4.tgz" }, "nodemailer": { "version": "0.7.1", - "from": "nodemailer@0.7.1", + "from": "https://registry.npmjs.org/nodemailer/-/nodemailer-0.7.1.tgz", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-0.7.1.tgz", "dependencies": { "mailcomposer": { "version": "0.2.12", - "from": "mailcomposer@>=0.2.10 <0.3.0", + "from": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-0.2.12.tgz", "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-0.2.12.tgz", "dependencies": { "mimelib": { "version": "0.2.19", - "from": "mimelib@>=0.2.15 <0.3.0", + "from": "https://registry.npmjs.org/mimelib/-/mimelib-0.2.19.tgz", "resolved": "https://registry.npmjs.org/mimelib/-/mimelib-0.2.19.tgz", "dependencies": { "encoding": { "version": "0.1.12", - "from": "encoding@>=0.1.7 <0.2.0", + "from": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "dependencies": { "iconv-lite": { "version": "0.4.13", - "from": "iconv-lite@>=0.4.13 <0.5.0", + "from": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz" } } }, "addressparser": { "version": "0.3.2", - "from": "addressparser@>=0.3.2 <0.4.0", + "from": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz", "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-0.3.2.tgz" } } }, "mime": { "version": "1.2.11", - "from": "mime@>=1.2.11 <1.3.0", + "from": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz" }, "follow-redirects": { "version": "0.0.3", - "from": "follow-redirects@0.0.3", + "from": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.3.tgz", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.3.tgz", "dependencies": { "underscore": { "version": "1.8.3", - "from": "underscore@latest", + "from": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz" } } }, "dkim-signer": { "version": "0.1.2", - "from": "dkim-signer@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/dkim-signer/-/dkim-signer-0.1.2.tgz", "resolved": "https://registry.npmjs.org/dkim-signer/-/dkim-signer-0.1.2.tgz", "dependencies": { "punycode": { "version": "1.2.4", - "from": "punycode@>=1.2.4 <1.3.0", + "from": "https://registry.npmjs.org/punycode/-/punycode-1.2.4.tgz", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.2.4.tgz" } } @@ -2789,71 +2782,71 @@ }, "directmail": { "version": "0.1.8", - "from": "directmail@>=0.1.7 <0.2.0", + "from": "https://registry.npmjs.org/directmail/-/directmail-0.1.8.tgz", "resolved": "https://registry.npmjs.org/directmail/-/directmail-0.1.8.tgz" }, "he": { "version": "0.3.6", - "from": "he@>=0.3.6 <0.4.0", + "from": "https://registry.npmjs.org/he/-/he-0.3.6.tgz", "resolved": "https://registry.npmjs.org/he/-/he-0.3.6.tgz" }, "public-address": { "version": "0.1.1", - "from": "public-address@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/public-address/-/public-address-0.1.1.tgz", "resolved": "https://registry.npmjs.org/public-address/-/public-address-0.1.1.tgz" }, "aws-sdk": { "version": "2.0.5", - "from": "aws-sdk@2.0.5", + "from": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.0.5.tgz", "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.0.5.tgz", "dependencies": { "aws-sdk-apis": { "version": "3.1.10", - "from": "aws-sdk-apis@>=3.0.0 <4.0.0", + "from": "https://registry.npmjs.org/aws-sdk-apis/-/aws-sdk-apis-3.1.10.tgz", "resolved": "https://registry.npmjs.org/aws-sdk-apis/-/aws-sdk-apis-3.1.10.tgz" }, "xml2js": { "version": "0.2.6", - "from": "xml2js@0.2.6", + "from": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.6.tgz", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.2.6.tgz", "dependencies": { "sax": { "version": "0.4.2", - "from": "sax@0.4.2", + "from": "https://registry.npmjs.org/sax/-/sax-0.4.2.tgz", "resolved": "https://registry.npmjs.org/sax/-/sax-0.4.2.tgz" } } }, "xmlbuilder": { "version": "0.4.2", - "from": "xmlbuilder@0.4.2", + "from": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.2.tgz", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-0.4.2.tgz" } } }, "readable-stream": { "version": "1.1.14", - "from": "readable-stream@>=1.1.9 <1.2.0", + "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "dependencies": { "core-util-is": { "version": "1.0.2", - "from": "core-util-is@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" }, "isarray": { "version": "0.0.1", - "from": "isarray@0.0.1", + "from": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" }, "string_decoder": { "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0", + "from": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.1 <2.1.0", + "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" } } @@ -2862,37 +2855,37 @@ }, "po2json": { "version": "0.4.1", - "from": "po2json@0.4.1", + "from": "https://registry.npmjs.org/po2json/-/po2json-0.4.1.tgz", "resolved": "https://registry.npmjs.org/po2json/-/po2json-0.4.1.tgz", "dependencies": { "nomnom": { "version": "1.8.1", - "from": "nomnom@1.8.1", + "from": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", "dependencies": { "underscore": { "version": "1.6.0", - "from": "underscore@>=1.6.0 <1.7.0", + "from": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz" }, "chalk": { "version": "0.4.0", - "from": "chalk@>=0.4.0 <0.5.0", + "from": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", "dependencies": { "has-color": { "version": "0.1.7", - "from": "has-color@>=0.1.0 <0.2.0", + "from": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz" }, "ansi-styles": { "version": "1.0.0", - "from": "ansi-styles@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz" }, "strip-ansi": { "version": "0.1.1", - "from": "strip-ansi@>=0.1.0 <0.2.0", + "from": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz" } } @@ -2901,17 +2894,17 @@ }, "gettext-parser": { "version": "1.1.0", - "from": "gettext-parser@1.1.0", + "from": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.1.0.tgz", "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.1.0.tgz", "dependencies": { "encoding": { "version": "0.1.12", - "from": "encoding@>=0.1.11 <0.2.0", + "from": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "dependencies": { "iconv-lite": { "version": "0.4.13", - "from": "iconv-lite@>=0.4.13 <0.5.0", + "from": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz" } } @@ -2922,76 +2915,57 @@ }, "request": { "version": "2.69.0", - "from": "request@2.69.0", + "from": "https://registry.npmjs.org/request/-/request-2.69.0.tgz", "resolved": "https://registry.npmjs.org/request/-/request-2.69.0.tgz", "dependencies": { "aws-sign2": { "version": "0.6.0", - "from": "aws-sign2@>=0.6.0 <0.7.0", + "from": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz" }, "aws4": { - "version": "1.3.2", - "from": "aws4@>=1.2.1 <2.0.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.3.2.tgz", - "dependencies": { - "lru-cache": { - "version": "4.0.1", - "from": "lru-cache@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.1.tgz", - "dependencies": { - "pseudomap": { - "version": "1.0.2", - "from": "pseudomap@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz" - }, - "yallist": { - "version": "2.0.0", - "from": "yallist@>=2.0.0 <3.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz" - } - } - } - } + "version": "1.4.1", + "from": "https://registry.npmjs.org/aws4/-/aws4-1.4.1.tgz", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.4.1.tgz" }, "bl": { "version": "1.0.3", - "from": "bl@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz", "dependencies": { "readable-stream": { "version": "2.0.6", - "from": "readable-stream@>=2.0.5 <2.1.0", + "from": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "dependencies": { "core-util-is": { "version": "1.0.2", - "from": "core-util-is@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.1 <2.1.0", + "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, "isarray": { "version": "1.0.0", - "from": "isarray@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "process-nextick-args": { - "version": "1.0.6", - "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz" + "version": "1.0.7", + "from": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" }, "string_decoder": { "version": "0.10.31", - "from": "string_decoder@>=0.10.0 <0.11.0", + "from": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" }, "util-deprecate": { "version": "1.0.2", - "from": "util-deprecate@>=1.0.1 <1.1.0", + "from": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" } } @@ -3000,148 +2974,148 @@ }, "caseless": { "version": "0.11.0", - "from": "caseless@>=0.11.0 <0.12.0", + "from": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz" }, "combined-stream": { "version": "1.0.5", - "from": "combined-stream@>=1.0.5 <1.1.0", + "from": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", "dependencies": { "delayed-stream": { "version": "1.0.0", - "from": "delayed-stream@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" } } }, "extend": { "version": "3.0.0", - "from": "extend@>=3.0.0 <3.1.0", + "from": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz" }, "forever-agent": { "version": "0.6.1", - "from": "forever-agent@>=0.6.1 <0.7.0", + "from": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" }, "form-data": { "version": "1.0.0-rc4", - "from": "form-data@>=1.0.0-rc3 <1.1.0", + "from": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.0-rc4.tgz", "dependencies": { "async": { "version": "1.5.2", - "from": "async@>=1.5.2 <2.0.0", + "from": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz" } } }, "har-validator": { "version": "2.0.6", - "from": "har-validator@>=2.0.6 <2.1.0", + "from": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", "dependencies": { "chalk": { "version": "1.1.3", - "from": "chalk@>=1.1.1 <2.0.0", + "from": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "dependencies": { "ansi-styles": { "version": "2.2.1", - "from": "ansi-styles@>=2.2.1 <3.0.0", + "from": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" }, "escape-string-regexp": { "version": "1.0.5", - "from": "escape-string-regexp@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" }, "has-ansi": { "version": "2.0.0", - "from": "has-ansi@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" } } }, "strip-ansi": { "version": "3.0.1", - "from": "strip-ansi@>=3.0.0 <4.0.0", + "from": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "dependencies": { "ansi-regex": { "version": "2.0.0", - "from": "ansi-regex@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" } } }, "supports-color": { "version": "2.0.0", - "from": "supports-color@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" } } }, "commander": { "version": "2.9.0", - "from": "commander@>=2.9.0 <3.0.0", + "from": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "dependencies": { "graceful-readlink": { "version": "1.0.1", - "from": "graceful-readlink@>=1.0.0", + "from": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" } } }, "is-my-json-valid": { "version": "2.13.1", - "from": "is-my-json-valid@>=2.12.4 <3.0.0", + "from": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz", "dependencies": { "generate-function": { "version": "2.0.0", - "from": "generate-function@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz" }, "generate-object-property": { "version": "1.2.0", - "from": "generate-object-property@>=1.1.0 <2.0.0", + "from": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "dependencies": { "is-property": { "version": "1.0.2", - "from": "is-property@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz" } } }, "jsonpointer": { "version": "2.0.0", - "from": "jsonpointer@2.0.0", + "from": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" }, "xtend": { "version": "4.0.1", - "from": "xtend@>=4.0.0 <5.0.0", + "from": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" } } }, "pinkie-promise": { "version": "2.0.1", - "from": "pinkie-promise@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "dependencies": { "pinkie": { "version": "2.0.4", - "from": "pinkie@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" } } @@ -3150,106 +3124,106 @@ }, "hawk": { "version": "3.1.3", - "from": "hawk@>=3.1.0 <3.2.0", + "from": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "dependencies": { "hoek": { "version": "2.16.3", - "from": "hoek@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" }, "boom": { "version": "2.10.1", - "from": "boom@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" }, "cryptiles": { "version": "2.0.5", - "from": "cryptiles@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz" }, "sntp": { "version": "1.0.9", - "from": "sntp@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" } } }, "http-signature": { "version": "1.1.1", - "from": "http-signature@>=1.1.0 <1.2.0", + "from": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "dependencies": { "assert-plus": { "version": "0.2.0", - "from": "assert-plus@>=0.2.0 <0.3.0", + "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz" }, "jsprim": { "version": "1.2.2", - "from": "jsprim@>=1.2.2 <2.0.0", + "from": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz", "dependencies": { "extsprintf": { "version": "1.0.2", - "from": "extsprintf@1.0.2", + "from": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz" }, "json-schema": { "version": "0.2.2", - "from": "json-schema@0.2.2", + "from": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz" }, "verror": { "version": "1.3.6", - "from": "verror@1.3.6", + "from": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz" } } }, "sshpk": { "version": "1.8.3", - "from": "sshpk@>=1.7.0 <2.0.0", + "from": "https://registry.npmjs.org/sshpk/-/sshpk-1.8.3.tgz", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.8.3.tgz", "dependencies": { "asn1": { "version": "0.2.3", - "from": "asn1@>=0.2.3 <0.3.0", + "from": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz" }, "assert-plus": { "version": "1.0.0", - "from": "assert-plus@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" }, "dashdash": { - "version": "1.13.1", - "from": "dashdash@>=1.12.0 <2.0.0", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.1.tgz" + "version": "1.14.0", + "from": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.0.tgz" }, "getpass": { "version": "0.1.6", - "from": "getpass@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz" }, "jsbn": { "version": "0.1.0", - "from": "jsbn@>=0.1.0 <0.2.0", + "from": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz" }, "tweetnacl": { "version": "0.13.3", - "from": "tweetnacl@>=0.13.0 <0.14.0", + "from": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.13.3.tgz" }, "jodid25519": { "version": "1.0.2", - "from": "jodid25519@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz" }, "ecc-jsbn": { "version": "0.1.1", - "from": "ecc-jsbn@>=0.1.1 <0.2.0", + "from": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz" } } @@ -3258,157 +3232,145 @@ }, "is-typedarray": { "version": "1.0.0", - "from": "is-typedarray@>=1.0.0 <1.1.0", + "from": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" }, "isstream": { "version": "0.1.2", - "from": "isstream@>=0.1.2 <0.2.0", + "from": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" }, "json-stringify-safe": { "version": "5.0.1", - "from": "json-stringify-safe@>=5.0.1 <5.1.0", + "from": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" }, "mime-types": { "version": "2.1.11", - "from": "mime-types@>=2.1.7 <2.2.0", + "from": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.11.tgz", "dependencies": { "mime-db": { "version": "1.23.0", - "from": "mime-db@>=1.23.0 <1.24.0", + "from": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.23.0.tgz" } } }, "node-uuid": { "version": "1.4.7", - "from": "node-uuid@>=1.4.7 <1.5.0", + "from": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz" }, "oauth-sign": { - "version": "0.8.1", - "from": "oauth-sign@>=0.8.0 <0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.1.tgz" + "version": "0.8.2", + "from": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz" }, "qs": { "version": "6.0.2", - "from": "qs@>=6.0.2 <6.1.0", + "from": "https://registry.npmjs.org/qs/-/qs-6.0.2.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.0.2.tgz" }, "stringstream": { "version": "0.0.5", - "from": "stringstream@>=0.0.4 <0.1.0", + "from": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz" }, "tough-cookie": { "version": "2.2.2", - "from": "tough-cookie@>=2.2.0 <2.3.0", + "from": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz" }, "tunnel-agent": { - "version": "0.4.2", - "from": "tunnel-agent@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz" + "version": "0.4.3", + "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" } } }, "restify": { "version": "4.0.3", - "from": "restify@4.0.3", + "from": "https://registry.npmjs.org/restify/-/restify-4.0.3.tgz", "resolved": "https://registry.npmjs.org/restify/-/restify-4.0.3.tgz", "dependencies": { "assert-plus": { "version": "0.1.5", - "from": "assert-plus@>=0.1.5 <0.2.0", + "from": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" }, "backoff": { "version": "2.5.0", - "from": "backoff@>=2.4.0 <3.0.0", + "from": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", "dependencies": { "precond": { "version": "0.2.3", - "from": "precond@>=0.2.0 <0.3.0", + "from": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz" } } }, "bunyan": { "version": "1.8.1", - "from": "bunyan@>=1.4.0 <2.0.0", + "from": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.1.tgz", "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.1.tgz", "dependencies": { "mv": { "version": "2.1.1", - "from": "mv@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", "dependencies": { - "mkdirp": { - "version": "0.5.1", - "from": "mkdirp@>=0.5.1 <0.6.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "dependencies": { - "minimist": { - "version": "0.0.8", - "from": "minimist@0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" - } - } - }, "ncp": { "version": "2.0.0", - "from": "ncp@>=2.0.0 <2.1.0", + "from": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz" }, "rimraf": { "version": "2.4.5", - "from": "rimraf@>=2.4.0 <2.5.0", + "from": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", "dependencies": { "glob": { "version": "6.0.4", - "from": "glob@>=6.0.1 <7.0.0", + "from": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", "dependencies": { "inflight": { - "version": "1.0.4", - "from": "inflight@>=1.0.4 <2.0.0", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", + "version": "1.0.5", + "from": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", "dependencies": { "wrappy": { - "version": "1.0.1", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + "version": "1.0.2", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" } } }, "inherits": { "version": "2.0.1", - "from": "inherits@>=2.0.0 <3.0.0", + "from": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, "minimatch": { - "version": "3.0.0", - "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", + "version": "3.0.2", + "from": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", "dependencies": { "brace-expansion": { - "version": "1.1.4", - "from": "brace-expansion@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.4.tgz", + "version": "1.1.5", + "from": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", "dependencies": { "balanced-match": { "version": "0.4.1", - "from": "balanced-match@>=0.4.1 <0.5.0", + "from": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" }, "concat-map": { "version": "0.0.1", - "from": "concat-map@0.0.1", + "from": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" } } @@ -3417,7 +3379,7 @@ }, "path-is-absolute": { "version": "1.0.0", - "from": "path-is-absolute@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" } } @@ -3428,140 +3390,140 @@ }, "safe-json-stringify": { "version": "1.0.3", - "from": "safe-json-stringify@>=1.0.0 <2.0.0", + "from": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.0.3.tgz", "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.0.3.tgz" }, "moment": { "version": "2.13.0", - "from": "moment@>=2.10.6 <3.0.0", + "from": "https://registry.npmjs.org/moment/-/moment-2.13.0.tgz", "resolved": "https://registry.npmjs.org/moment/-/moment-2.13.0.tgz" } } }, "csv": { "version": "0.4.6", - "from": "csv@>=0.4.0 <0.5.0", + "from": "https://registry.npmjs.org/csv/-/csv-0.4.6.tgz", "resolved": "https://registry.npmjs.org/csv/-/csv-0.4.6.tgz", "dependencies": { "csv-generate": { "version": "0.0.6", - "from": "csv-generate@>=0.0.6 <0.0.7", + "from": "https://registry.npmjs.org/csv-generate/-/csv-generate-0.0.6.tgz", "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-0.0.6.tgz" }, "csv-parse": { - "version": "1.1.0", - "from": "csv-parse@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.1.0.tgz" + "version": "1.1.1", + "from": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-1.1.1.tgz" }, "stream-transform": { "version": "0.1.1", - "from": "stream-transform@>=0.1.0 <0.2.0", + "from": "https://registry.npmjs.org/stream-transform/-/stream-transform-0.1.1.tgz", "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-0.1.1.tgz" }, "csv-stringify": { "version": "0.0.8", - "from": "csv-stringify@>=0.0.8 <0.0.9", + "from": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-0.0.8.tgz", "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-0.0.8.tgz" } } }, "escape-regexp-component": { "version": "1.0.2", - "from": "escape-regexp-component@>=1.0.2 <2.0.0", + "from": "https://registry.npmjs.org/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz", "resolved": "https://registry.npmjs.org/escape-regexp-component/-/escape-regexp-component-1.0.2.tgz" }, "formidable": { "version": "1.0.17", - "from": "formidable@>=1.0.14 <2.0.0", + "from": "https://registry.npmjs.org/formidable/-/formidable-1.0.17.tgz", "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.17.tgz" }, "http-signature": { "version": "0.11.0", - "from": "http-signature@>=0.11.0 <0.12.0", + "from": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.11.0.tgz", "dependencies": { "asn1": { "version": "0.1.11", - "from": "asn1@0.1.11", + "from": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz" }, "ctype": { "version": "0.5.3", - "from": "ctype@0.5.3", + "from": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz" } } }, "keep-alive-agent": { "version": "0.0.1", - "from": "keep-alive-agent@>=0.0.1 <0.0.2", + "from": "https://registry.npmjs.org/keep-alive-agent/-/keep-alive-agent-0.0.1.tgz", "resolved": "https://registry.npmjs.org/keep-alive-agent/-/keep-alive-agent-0.0.1.tgz" }, "lru-cache": { "version": "2.7.3", - "from": "lru-cache@>=2.5.0 <3.0.0", + "from": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz" }, "mime": { "version": "1.3.4", - "from": "mime@>=1.2.11 <2.0.0", + "from": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz" }, "negotiator": { "version": "0.5.3", - "from": "negotiator@>=0.5.1 <0.6.0", + "from": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz" }, "node-uuid": { "version": "1.4.7", - "from": "node-uuid@>=1.4.1 <2.0.0", + "from": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz", "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz" }, "once": { "version": "1.3.3", - "from": "once@>=1.3.0 <2.0.0", + "from": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "dependencies": { "wrappy": { - "version": "1.0.1", - "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + "version": "1.0.2", + "from": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" } } }, "qs": { "version": "3.1.0", - "from": "qs@>=3.1.0 <4.0.0", + "from": "https://registry.npmjs.org/qs/-/qs-3.1.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-3.1.0.tgz" }, "semver": { "version": "4.3.6", - "from": "semver@>=4.3.3 <5.0.0", + "from": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz" }, "spdy": { "version": "1.32.5", - "from": "spdy@>=1.26.5 <2.0.0", + "from": "https://registry.npmjs.org/spdy/-/spdy-1.32.5.tgz", "resolved": "https://registry.npmjs.org/spdy/-/spdy-1.32.5.tgz" }, "tunnel-agent": { - "version": "0.4.2", - "from": "tunnel-agent@>=0.4.0 <0.5.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz" + "version": "0.4.3", + "from": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" }, "vasync": { "version": "1.6.3", - "from": "vasync@1.6.3", + "from": "https://registry.npmjs.org/vasync/-/vasync-1.6.3.tgz", "resolved": "https://registry.npmjs.org/vasync/-/vasync-1.6.3.tgz", "dependencies": { "verror": { "version": "1.6.0", - "from": "verror@1.6.0", + "from": "https://registry.npmjs.org/verror/-/verror-1.6.0.tgz", "resolved": "https://registry.npmjs.org/verror/-/verror-1.6.0.tgz", "dependencies": { "extsprintf": { "version": "1.2.0", - "from": "extsprintf@1.2.0", + "from": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.2.0.tgz", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.2.0.tgz" } } @@ -3570,34 +3532,63 @@ }, "verror": { "version": "1.6.1", - "from": "verror@>=1.4.0 <2.0.0", + "from": "https://registry.npmjs.org/verror/-/verror-1.6.1.tgz", "resolved": "https://registry.npmjs.org/verror/-/verror-1.6.1.tgz", "dependencies": { "core-util-is": { "version": "1.0.2", - "from": "core-util-is@1.0.2", + "from": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" }, "extsprintf": { "version": "1.2.0", - "from": "extsprintf@1.2.0", + "from": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.2.0.tgz", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.2.0.tgz" } } }, "dtrace-provider": { "version": "0.6.0", - "from": "dtrace-provider@>=0.6.0 <0.7.0", + "from": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz", "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.6.0.tgz", "dependencies": { "nan": { - "version": "2.3.3", - "from": "nan@>=2.0.8 <3.0.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.3.tgz" + "version": "2.3.5", + "from": "https://registry.npmjs.org/nan/-/nan-2.3.5.tgz", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.3.5.tgz" } } } } + }, + "mkdirp": { + "version": "0.5.1", + "from": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "dependencies": { + "minimist": { + "version": "0.0.8", + "from": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" + } + } + }, + "simplesmtp": { + "version": "0.3.32", + "from": "https://registry.npmjs.org/simplesmtp/-/simplesmtp-0.3.32.tgz", + "resolved": "https://registry.npmjs.org/simplesmtp/-/simplesmtp-0.3.32.tgz", + "dependencies": { + "rai": { + "version": "0.1.12", + "from": "https://registry.npmjs.org/rai/-/rai-0.1.12.tgz", + "resolved": "https://registry.npmjs.org/rai/-/rai-0.1.12.tgz" + }, + "xoauth2": { + "version": "0.1.8", + "from": "https://registry.npmjs.org/xoauth2/-/xoauth2-0.1.8.tgz", + "resolved": "https://registry.npmjs.org/xoauth2/-/xoauth2-0.1.8.tgz" + } + } } } }, @@ -3676,7 +3667,7 @@ }, "lodash.isarray": { "version": "3.0.4", - "from": "lodash.isarray@>=3.0.0 <4.0.0", + "from": "lodash.isarray@3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz" }, "lodash.keys": { @@ -3831,7 +3822,7 @@ }, "lodash": { "version": "2.4.2", - "from": "lodash@2.4.2", + "from": "lodash@>=2.4.1 <2.5.0", "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz" } } @@ -3882,13 +3873,13 @@ }, "nopt": { "version": "1.0.10", - "from": "nopt@>=1.0.10 <1.1.0", + "from": "nopt@1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", "dependencies": { "abbrev": { - "version": "1.0.7", + "version": "1.0.9", "from": "abbrev@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" } } }, @@ -4003,9 +3994,9 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", "dependencies": { "abbrev": { - "version": "1.0.7", + "version": "1.0.9", "from": "abbrev@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" } } }, @@ -4139,9 +4130,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "process-nextick-args": { - "version": "1.0.6", + "version": "1.0.7", "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz" + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" }, "string_decoder": { "version": "0.10.31", @@ -4253,9 +4244,9 @@ } }, "uglify-js": { - "version": "2.6.2", + "version": "2.6.4", "from": "uglify-js@>=2.6.0 <3.0.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.2.tgz", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz", "dependencies": { "async": { "version": "0.2.10", @@ -4388,9 +4379,9 @@ } }, "lodash": { - "version": "4.11.2", + "version": "4.13.1", "from": "lodash@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.11.2.tgz" + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz" }, "split": { "version": "1.0.0", @@ -4405,9 +4396,9 @@ "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-0.1.2.tgz", "dependencies": { "JSONStream": { - "version": "1.1.1", + "version": "1.1.2", "from": "JSONStream@>=1.0.4 <2.0.0", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.1.2.tgz", "dependencies": { "jsonparse": { "version": "1.2.0", @@ -4458,9 +4449,9 @@ "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-0.1.0.tgz", "dependencies": { "hosted-git-info": { - "version": "2.1.4", + "version": "2.1.5", "from": "hosted-git-info@>=2.1.4 <3.0.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz" }, "normalize-package-data": { "version": "2.3.5", @@ -4652,19 +4643,26 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" }, "loud-rejection": { - "version": "1.3.0", + "version": "1.5.0", "from": "loud-rejection@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.5.0.tgz", "dependencies": { - "array-find-index": { - "version": "1.0.1", - "from": "array-find-index@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.1.tgz" + "currently-unhandled": { + "version": "0.4.1", + "from": "currently-unhandled@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "dependencies": { + "array-find-index": { + "version": "1.0.1", + "from": "array-find-index@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.1.tgz" + } + } }, "signal-exit": { - "version": "2.1.2", - "from": "signal-exit@>=2.1.2 <3.0.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-2.1.2.tgz" + "version": "3.0.0", + "from": "signal-exit@>=3.0.0 <4.0.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.0.tgz" } } }, @@ -4680,13 +4678,13 @@ }, "normalize-package-data": { "version": "2.3.5", - "from": "normalize-package-data@>=2.3.4 <3.0.0", + "from": "normalize-package-data@>=2.3.2 <3.0.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", "dependencies": { "hosted-git-info": { - "version": "2.1.4", + "version": "2.1.5", "from": "hosted-git-info@>=2.1.4 <3.0.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz" }, "is-builtin-module": { "version": "1.0.0", @@ -4729,7 +4727,7 @@ }, "spdx-license-ids": { "version": "1.2.1", - "from": "spdx-license-ids@>=1.0.2 <2.0.0", + "from": "spdx-license-ids@>=1.0.0 <2.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.1.tgz" } } @@ -4806,9 +4804,9 @@ "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "dependencies": { "graceful-fs": { - "version": "4.1.3", + "version": "4.1.4", "from": "graceful-fs@>=4.1.2 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz" }, "parse-json": { "version": "2.2.0", @@ -4866,9 +4864,9 @@ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz", "dependencies": { "hosted-git-info": { - "version": "2.1.4", + "version": "2.1.5", "from": "hosted-git-info@>=2.1.4 <3.0.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz" + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz" }, "is-builtin-module": { "version": "1.0.0", @@ -4926,9 +4924,9 @@ "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", "dependencies": { "graceful-fs": { - "version": "4.1.3", + "version": "4.1.4", "from": "graceful-fs@>=4.1.2 <5.0.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz" + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.4.tgz" }, "pify": { "version": "2.3.0", @@ -5030,9 +5028,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "process-nextick-args": { - "version": "1.0.6", + "version": "1.0.7", "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz" + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" }, "string_decoder": { "version": "0.10.31", @@ -5061,9 +5059,9 @@ "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", "dependencies": { "irregular-plurals": { - "version": "1.1.0", + "version": "1.2.0", "from": "irregular-plurals@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.1.0.tgz" + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.2.0.tgz" } } }, @@ -5166,9 +5164,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "process-nextick-args": { - "version": "1.0.6", + "version": "1.0.7", "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz" + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" }, "string_decoder": { "version": "0.10.31", @@ -5224,9 +5222,9 @@ "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", "dependencies": { "es6-map": { - "version": "0.1.3", + "version": "0.1.4", "from": "es6-map@>=0.1.3 <0.2.0", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.3.tgz", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.4.tgz", "dependencies": { "d": { "version": "0.1.1", @@ -5235,8 +5233,15 @@ }, "es5-ext": { "version": "0.10.11", - "from": "es5-ext@>=0.10.8 <0.11.0", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.11.tgz" + "from": "es5-ext@>=0.10.11 <0.11.0", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.11.tgz", + "dependencies": { + "es6-symbol": { + "version": "3.0.2", + "from": "es6-symbol@>=3.0.2 <3.1.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.0.2.tgz" + } + } }, "es6-iterator": { "version": "2.0.0", @@ -5249,9 +5254,9 @@ "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.4.tgz" }, "es6-symbol": { - "version": "3.0.2", - "from": "es6-symbol@>=3.0.1 <3.1.0", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.0.2.tgz" + "version": "3.1.0", + "from": "es6-symbol@>=3.1.0 <3.2.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz" }, "event-emitter": { "version": "0.3.4", @@ -5273,7 +5278,14 @@ "es5-ext": { "version": "0.10.11", "from": "es5-ext@>=0.10.8 <0.11.0", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.11.tgz" + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.11.tgz", + "dependencies": { + "es6-symbol": { + "version": "3.0.2", + "from": "es6-symbol@>=3.0.2 <3.1.0", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.0.2.tgz" + } + } }, "es6-iterator": { "version": "2.0.0", @@ -5281,9 +5293,9 @@ "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.0.tgz" }, "es6-symbol": { - "version": "3.0.2", + "version": "3.1.0", "from": "es6-symbol@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.0.2.tgz" + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.0.tgz" } } }, @@ -5347,9 +5359,16 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz" }, "figures": { - "version": "1.5.0", + "version": "1.7.0", "from": "figures@>=1.3.5 <2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.5.0.tgz" + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "dependencies": { + "object-assign": { + "version": "4.1.0", + "from": "object-assign@>=4.1.0 <5.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz" + } + } }, "lodash": { "version": "3.10.1", @@ -5415,9 +5434,9 @@ } }, "js-yaml": { - "version": "3.6.0", + "version": "3.6.1", "from": "js-yaml@>=3.2.5 <4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.0.tgz", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", "dependencies": { "argparse": { "version": "1.0.7", @@ -5444,9 +5463,9 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "dependencies": { "brace-expansion": { - "version": "1.1.4", + "version": "1.1.5", "from": "brace-expansion@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.4.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", "dependencies": { "balanced-match": { "version": "0.4.1", @@ -5545,6 +5564,95 @@ } } }, + "grunt-newer": { + "version": "1.2.0", + "from": "grunt-newer@1.2.0", + "resolved": "https://registry.npmjs.org/grunt-newer/-/grunt-newer-1.2.0.tgz", + "dependencies": { + "async": { + "version": "1.5.2", + "from": "async@>=1.5.2 <2.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz" + }, + "rimraf": { + "version": "2.5.2", + "from": "rimraf@>=2.5.2 <3.0.0", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz", + "dependencies": { + "glob": { + "version": "7.0.5", + "from": "glob@>=7.0.0 <8.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.5.tgz", + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "from": "fs.realpath@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + }, + "inflight": { + "version": "1.0.5", + "from": "inflight@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", + "dependencies": { + "wrappy": { + "version": "1.0.2", + "from": "wrappy@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + } + } + }, + "inherits": { + "version": "2.0.1", + "from": "inherits@>=2.0.0 <3.0.0", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" + }, + "minimatch": { + "version": "3.0.2", + "from": "minimatch@>=3.0.2 <4.0.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", + "dependencies": { + "brace-expansion": { + "version": "1.1.5", + "from": "brace-expansion@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", + "dependencies": { + "balanced-match": { + "version": "0.4.1", + "from": "balanced-match@>=0.4.1 <0.5.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.1.tgz" + }, + "concat-map": { + "version": "0.0.1", + "from": "concat-map@0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + } + } + } + } + }, + "once": { + "version": "1.3.3", + "from": "once@>=1.3.0 <2.0.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "dependencies": { + "wrappy": { + "version": "1.0.2", + "from": "wrappy@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + } + } + }, + "path-is-absolute": { + "version": "1.0.0", + "from": "path-is-absolute@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" + } + } + } + } + } + } + }, "grunt-nsp": { "version": "2.1.2", "from": "grunt-nsp@2.1.2", @@ -5609,16 +5717,16 @@ "from": "wreck@6.3.0", "resolved": "https://registry.npmjs.org/wreck/-/wreck-6.3.0.tgz" }, - "agent-base": { - "version": "2.0.1", - "from": "agent-base@2.0.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz" - }, "ansi": { "version": "0.3.0", "from": "ansi@0.3.0", "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.0.tgz" }, + "agent-base": { + "version": "2.0.1", + "from": "agent-base@2.0.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz" + }, "boom": { "version": "2.10.1", "from": "boom@2.10.1", @@ -5669,16 +5777,16 @@ "from": "graceful-fs@3.0.8", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz" }, - "has-unicode": { - "version": "1.0.1", - "from": "has-unicode@1.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz" - }, "hoek": { "version": "2.16.3", "from": "hoek@2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz" }, + "has-unicode": { + "version": "1.0.1", + "from": "has-unicode@1.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-1.0.1.tgz" + }, "hosted-git-info": { "version": "2.1.4", "from": "hosted-git-info@2.1.4", @@ -5764,20 +5872,20 @@ "from": "slide@*", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz" }, - "spdx-correct": { - "version": "1.0.2", - "from": "spdx-correct@1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz" + "spdx-expression-parse": { + "version": "1.0.0", + "from": "spdx-expression-parse@1.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.0.tgz" }, "spdx-exceptions": { "version": "1.0.3", "from": "spdx-exceptions@1.0.3", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.3.tgz" }, - "spdx-expression-parse": { - "version": "1.0.0", - "from": "spdx-expression-parse@1.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.0.tgz" + "spdx-correct": { + "version": "1.0.2", + "from": "spdx-correct@1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz" }, "spdx-license-ids": { "version": "1.1.0", @@ -5857,7 +5965,7 @@ }, "concat-stream": { "version": "1.5.1", - "from": "concat-stream@1.5.1", + "from": "concat-stream@>=1.5.0 <2.0.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.1.tgz" }, "core-util-is": { @@ -5882,7 +5990,7 @@ }, "has-ansi": { "version": "2.0.0", - "from": "has-ansi@2.0.0", + "from": "has-ansi@>=2.0.0 <3.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" }, "inflight": { @@ -5895,16 +6003,16 @@ "from": "inherits@2.0.1", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" }, - "isarray": { - "version": "0.0.1", - "from": "isarray@0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - }, "minimatch": { "version": "2.0.10", "from": "minimatch@2.0.10", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz" }, + "isarray": { + "version": "0.0.1", + "from": "isarray@0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + }, "minimist": { "version": "0.0.8", "from": "minimist@0.0.8", @@ -6343,15 +6451,10 @@ "from": "base64url@>=0.0.4 <0.1.0", "resolved": "https://registry.npmjs.org/base64url/-/base64url-0.0.6.tgz" }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "from": "buffer-equal-constant-time@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" - }, "ecdsa-sig-formatter": { - "version": "1.0.5", + "version": "1.0.7", "from": "ecdsa-sig-formatter@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.5.tgz", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz", "dependencies": { "base64-url": { "version": "1.2.2", @@ -6385,14 +6488,14 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-4.3.5.tgz", "dependencies": { "inflight": { - "version": "1.0.4", + "version": "1.0.5", "from": "inflight@>=1.0.4 <2.0.0", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", "dependencies": { "wrappy": { - "version": "1.0.1", + "version": "1.0.2", "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" } } }, @@ -6407,9 +6510,9 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "dependencies": { "brace-expansion": { - "version": "1.1.4", + "version": "1.1.5", "from": "brace-expansion@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.4.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", "dependencies": { "balanced-match": { "version": "0.4.1", @@ -6431,9 +6534,9 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "dependencies": { "wrappy": { - "version": "1.0.1", + "version": "1.0.2", "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" } } } @@ -6452,14 +6555,14 @@ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz" }, "array-union": { - "version": "1.0.1", - "from": "array-union@1.0.1", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.1.tgz", + "version": "1.0.2", + "from": "array-union@>=1.0.1 <2.0.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "dependencies": { "array-uniq": { - "version": "1.0.2", + "version": "1.0.3", "from": "array-uniq@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.2.tgz" + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" } } }, @@ -6469,14 +6572,14 @@ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" }, "minimatch": { - "version": "3.0.0", + "version": "3.0.2", "from": "minimatch@>=3.0.0 <4.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.2.tgz", "dependencies": { "brace-expansion": { - "version": "1.1.4", + "version": "1.1.5", "from": "brace-expansion@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.4.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", "dependencies": { "balanced-match": { "version": "0.4.1", @@ -6549,15 +6652,51 @@ } } }, + "memcached": { + "version": "2.2.2", + "from": "memcached@2.2.2", + "resolved": "https://registry.npmjs.org/memcached/-/memcached-2.2.2.tgz", + "dependencies": { + "hashring": { + "version": "3.2.0", + "from": "hashring@>=3.2.0 <3.3.0", + "resolved": "https://registry.npmjs.org/hashring/-/hashring-3.2.0.tgz", + "dependencies": { + "connection-parse": { + "version": "0.0.7", + "from": "connection-parse@>=0.0.0 <0.1.0", + "resolved": "https://registry.npmjs.org/connection-parse/-/connection-parse-0.0.7.tgz" + }, + "simple-lru-cache": { + "version": "0.0.2", + "from": "simple-lru-cache@>=0.0.0 <0.1.0", + "resolved": "https://registry.npmjs.org/simple-lru-cache/-/simple-lru-cache-0.0.2.tgz" + } + } + }, + "jackpot": { + "version": "0.0.6", + "from": "jackpot@>=0.0.6", + "resolved": "https://registry.npmjs.org/jackpot/-/jackpot-0.0.6.tgz", + "dependencies": { + "retry": { + "version": "0.6.0", + "from": "retry@0.6.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.6.0.tgz" + } + } + } + } + }, "mozlog": { "version": "2.0.5", "from": "mozlog@2.0.5", "resolved": "https://registry.npmjs.org/mozlog/-/mozlog-2.0.5.tgz", "dependencies": { "intel": { - "version": "1.1.0", + "version": "1.1.1", "from": "intel@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/intel/-/intel-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/intel/-/intel-1.1.1.tgz", "dependencies": { "chalk": { "version": "1.1.3", @@ -6621,9 +6760,9 @@ "resolved": "https://registry.npmjs.org/strftime/-/strftime-0.9.2.tgz" }, "symbol": { - "version": "0.2.3", - "from": "symbol@>=0.2.0 <0.3.0", - "resolved": "https://registry.npmjs.org/symbol/-/symbol-0.2.3.tgz" + "version": "0.3.0", + "from": "symbol@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/symbol/-/symbol-0.3.0.tgz" }, "utcstring": { "version": "0.1.0", @@ -6668,6 +6807,16 @@ } } }, + "propagate": { + "version": "0.3.1", + "from": "propagate@>=0.3.0 <0.4.0", + "resolved": "https://registry.npmjs.org/propagate/-/propagate-0.3.1.tgz" + }, + "lodash": { + "version": "2.4.1", + "from": "lodash@2.4.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz" + }, "debug": { "version": "1.0.4", "from": "debug@>=1.0.4 <2.0.0", @@ -6680,11 +6829,6 @@ } } }, - "lodash": { - "version": "2.4.1", - "from": "lodash@2.4.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.1.tgz" - }, "mkdirp": { "version": "0.5.1", "from": "mkdirp@>=0.5.0 <0.6.0", @@ -6696,11 +6840,6 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" } } - }, - "propagate": { - "version": "0.3.1", - "from": "propagate@>=0.3.0 <0.4.0", - "resolved": "https://registry.npmjs.org/propagate/-/propagate-0.3.1.tgz" } } }, @@ -6737,23 +6876,23 @@ } }, "es-abstract": { - "version": "1.5.0", + "version": "1.5.1", "from": "es-abstract@>=1.5.0 <2.0.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.5.0.tgz", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.5.1.tgz", "dependencies": { "function-bind": { "version": "1.1.0", - "from": "function-bind@>=1.0.2 <2.0.0", + "from": "function-bind@>=1.1.0 <2.0.0", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz" }, "is-callable": { "version": "1.1.3", - "from": "is-callable@>=1.1.1 <2.0.0", + "from": "is-callable@>=1.1.3 <2.0.0", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz" }, "es-to-primitive": { "version": "1.1.1", - "from": "es-to-primitive@>=1.1.0 <2.0.0", + "from": "es-to-primitive@>=1.1.1 <2.0.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", "dependencies": { "is-date-object": { @@ -6780,7 +6919,7 @@ "uap-core": { "version": "0.5.0", "from": "git://github.com/ua-parser/uap-core.git", - "resolved": "git://github.com/ua-parser/uap-core.git#02702aba680e53f9d5055acff195b96dfbf1e534" + "resolved": "git://github.com/ua-parser/uap-core.git#49b141ffe86d5138c332f733d6b2007675bbeb43" }, "uap-ref-impl": { "version": "0.2.0", @@ -6871,9 +7010,9 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" }, "process-nextick-args": { - "version": "1.0.6", + "version": "1.0.7", "from": "process-nextick-args@>=1.0.6 <1.1.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz" + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz" }, "string_decoder": { "version": "0.10.31", @@ -6944,9 +7083,9 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz" }, "tunnel-agent": { - "version": "0.4.2", + "version": "0.4.3", "from": "tunnel-agent@>=0.4.1 <0.5.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz" + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz" }, "tough-cookie": { "version": "2.2.2", @@ -6976,9 +7115,9 @@ } }, "oauth-sign": { - "version": "0.8.1", + "version": "0.8.2", "from": "oauth-sign@>=0.8.0 <0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.1.tgz" + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz" }, "hawk": { "version": "3.1.3", @@ -7087,7 +7226,7 @@ }, "commander": { "version": "2.9.0", - "from": "commander@>=2.9.0 <3.0.0", + "from": "commander@2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "dependencies": { "graceful-readlink": { @@ -7126,7 +7265,7 @@ }, "xtend": { "version": "4.0.1", - "from": "xtend@>=4.0.0 <5.0.0", + "from": "xtend@>=4.0.0 <4.1.0", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" } } @@ -7263,14 +7402,14 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", "dependencies": { "inflight": { - "version": "1.0.4", + "version": "1.0.5", "from": "inflight@>=1.0.4 <2.0.0", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.5.tgz", "dependencies": { "wrappy": { - "version": "1.0.1", + "version": "1.0.2", "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" } } }, @@ -7280,9 +7419,9 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", "dependencies": { "brace-expansion": { - "version": "1.1.4", + "version": "1.1.5", "from": "brace-expansion@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.4.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.5.tgz", "dependencies": { "balanced-match": { "version": "0.4.1", @@ -7304,9 +7443,9 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "dependencies": { "wrappy": { - "version": "1.0.1", + "version": "1.0.2", "from": "wrappy@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" } } } @@ -7335,9 +7474,9 @@ "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", "dependencies": { "abbrev": { - "version": "1.0.7", + "version": "1.0.9", "from": "abbrev@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" } } }, @@ -7422,23 +7561,23 @@ } }, "es-abstract": { - "version": "1.5.0", + "version": "1.5.1", "from": "es-abstract@>=1.5.0 <2.0.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.5.0.tgz", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.5.1.tgz", "dependencies": { "function-bind": { "version": "1.1.0", - "from": "function-bind@>=1.0.2 <2.0.0", + "from": "function-bind@>=1.1.0 <2.0.0", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz" }, "is-callable": { "version": "1.1.3", - "from": "is-callable@>=1.1.1 <2.0.0", + "from": "is-callable@>=1.1.3 <2.0.0", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz" }, "es-to-primitive": { "version": "1.1.1", - "from": "es-to-primitive@>=1.1.0 <2.0.0", + "from": "es-to-primitive@>=1.1.1 <2.0.0", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", "dependencies": { "is-date-object": { @@ -7463,14 +7602,14 @@ } }, "asn1.js": { - "version": "4.6.0", + "version": "4.6.2", "from": "asn1.js@>=4.5.2 <5.0.0", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.6.0.tgz", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.6.2.tgz", "dependencies": { "bn.js": { - "version": "4.11.3", + "version": "4.11.4", "from": "bn.js@>=4.0.0 <5.0.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.3.tgz" + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.4.tgz" }, "inherits": { "version": "2.0.1", @@ -7485,13 +7624,14 @@ } }, "bluebird": { - "version": "3.3.5", + "version": "3.4.1", "from": "bluebird@>=3.3.5 <4.0.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.3.5.tgz" + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.1.tgz" }, "buffer-compare-shim": { "version": "1.0.0", "from": "buffer-compare-shim@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/buffer-compare-shim/-/buffer-compare-shim-1.0.0.tgz", "dependencies": { "buffer-compare": { "version": "0.0.1", @@ -7523,14 +7663,14 @@ "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", "dependencies": { "bn.js": { - "version": "4.11.3", + "version": "4.11.4", "from": "bn.js@>=4.1.0 <5.0.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.3.tgz" + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.4.tgz" }, "elliptic": { - "version": "6.2.3", + "version": "6.3.1", "from": "elliptic@>=6.0.0 <7.0.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.2.3.tgz", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.1.tgz", "dependencies": { "brorand": { "version": "1.0.5", @@ -7602,7 +7742,8 @@ }, "buffer-io-shim": { "version": "1.0.0", - "from": "buffer-io-shim@>=1.0.0 <2.0.0" + "from": "buffer-io-shim@>=1.0.0 <2.0.0", + "resolved": "https://registry.npmjs.org/buffer-io-shim/-/buffer-io-shim-1.0.0.tgz" }, "semver": { "version": "5.1.0", @@ -7621,15 +7762,10 @@ "from": "jwa@>=1.1.2 <2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.3.tgz", "dependencies": { - "buffer-equal-constant-time": { - "version": "1.0.1", - "from": "buffer-equal-constant-time@>=1.0.1 <2.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" - }, "ecdsa-sig-formatter": { - "version": "1.0.5", + "version": "1.0.7", "from": "ecdsa-sig-formatter@>=1.0.0 <2.0.0", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.5.tgz", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.7.tgz", "dependencies": { "base64-url": { "version": "1.2.2", diff --git a/package.json b/package.json index 81bde5fd..99162dcd 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "hapi-fxa-oauth": "2.2.0", "hkdf": "0.0.2", "joi": "6.9.1", + "memcached": "2.2.2", "mozlog": "2.0.5", "node-statsd": "0.1.1", "node-uap": "git+https://github.com/vladikoff/node-uap.git#9cdd16247", diff --git a/test/local/account_routes.js b/test/local/account_routes.js index efdafedc..a3cd2a7d 100644 --- a/test/local/account_routes.js +++ b/test/local/account_routes.js @@ -26,10 +26,15 @@ var makeRoutes = function (options) { var config = options.config || {} config.verifierVersion = config.verifierVersion || 0 config.smtp = config.smtp || {} + config.memcached = config.memcached || { + address: '127.0.0.1:1121', + idle: 500, + lifetime: 30 + } var log = options.log || mocks.mockLog() - var Password = require('../../lib/crypto/password')(log, config) - var db = options.db || {} + var Password = options.Password || require('../../lib/crypto/password')(log, config) + var db = options.db || mocks.mockDB() var isPreVerified = require('../../lib/preverifier')(error, config) var customs = options.customs || { check: function () { return P.resolve(true) } @@ -211,10 +216,12 @@ test('/account/reset', function (t) { return P.resolve() }) } + var mockLog = mocks.spyLog() var mockPush = mocks.mockPush() var accountRoutes = makeRoutes({ - db: mockDB, customs: mockCustoms, + db: mockDB, + log: mockLog, push: mockPush }) var route = getRoute(accountRoutes, '/account/reset') @@ -228,6 +235,13 @@ test('/account/reset', function (t) { t.equal(mockDB.account.callCount, 1) t.equal(mockCustoms.reset.callCount, 1) + + t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once') + var args = mockLog.activityEvent.args[0] + t.equal(args.length, 3, 'log.activityEvent was passed three arguments') + t.equal(args[0], 'account.reset', 'first argument was event name') + t.equal(args[1], mockRequest, 'second argument was request object') + t.deepEqual(args[2], { uid: uid.toString('hex') }, 'third argument contained uid') }) }) @@ -271,16 +285,29 @@ test('/account/device', function (t) { t.equal(mockPush.notifyDeviceConnected.firstCall.args[1], device.name) t.equal(mockPush.notifyDeviceConnected.firstCall.args[2], deviceId) + t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once') + var args = mockLog.activityEvent.args[0] + t.equal(args.length, 3, 'log.activityEvent was passed three arguments') + t.equal(args[0], 'device.created', 'first argument was event name') + t.equal(args[1], mockRequest, 'second argument was request object') + t.deepEqual(args[2], { uid: uid.toString('hex'), device_id: deviceId }, 'third argument contained uid') + t.equal(mockLog.event.callCount, 1) - t.equal(mockLog.event.args[0].length, 3) - t.equal(mockLog.event.args[0][0], 'device:create') - t.deepEqual(mockLog.event.args[0][2], { + args = mockLog.event.args[0] + t.equal(args.length, 3) + t.equal(args[0], 'device:create') + t.equal(args[1], mockRequest) + t.deepEqual(args[2], { uid: uid.toString('hex'), id: deviceId, type: 'mobile', timestamp: deviceCreatedAt }) }) + .then(function () { + mockLog.activityEvent.reset() + mockLog.event.reset() + }) }, t) test('update', function (t) { @@ -322,6 +349,15 @@ test('/account/device', function (t) { return runTest(route, mockRequest, function (response) { t.equal(mockDB.updateDevice.callCount, 1, 'updateDevice was called') + t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once') + var args = mockLog.activityEvent.args[0] + t.equal(args.length, 3, 'log.activityEvent was passed three arguments') + t.equal(args[0], 'device.updated', 'first argument was event name') + t.equal(args[1], mockRequest, 'second argument was request object') + t.deepEqual(args[2], { uid: uid.toString('hex'), device_id: deviceId.toString('hex') }, 'third argument contained uid') + + t.equal(mockLog.event.callCount, 0, 'log.event was not called') + t.equal(mockLog.increment.callCount, 5, 'the counters were incremented') t.equal(mockLog.increment.getCall(0).args[0], 'device.update.sessionToken') t.equal(mockLog.increment.getCall(1).args[0], 'device.update.name') @@ -348,9 +384,7 @@ test('/account/device', function (t) { test('/account/device/destroy', function (t) { var uid = uuid.v4('binary') var deviceId = crypto.randomBytes(16).toString('hex') - var mockLog = mocks.mockLog({ - event: sinon.spy() - }) + var mockLog = mocks.spyLog() var mockDB = mocks.mockDB() var mockRequest = mocks.mockRequest({ credentials: { @@ -375,10 +409,19 @@ test('/account/device/destroy', function (t) { t.equal(mockPush.notifyDeviceDisconnected.firstCall.args[0], mockRequest.auth.credentials.uid) t.equal(mockPush.notifyDeviceDisconnected.firstCall.args[1], deviceId) + t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once') + var args = mockLog.activityEvent.args[0] + t.equal(args.length, 3, 'log.activityEvent was passed three arguments') + t.equal(args[0], 'device.deleted', 'first argument was event name') + t.equal(args[1], mockRequest, 'second argument was request object') + t.deepEqual(args[2], { uid: uid.toString('hex'), device_id: deviceId }, 'third argument contained uid and deviceId') + t.equal(mockLog.event.callCount, 1) - t.equal(mockLog.event.args[0].length, 3) - t.equal(mockLog.event.args[0][0], 'device:delete') - var details = mockLog.event.args[0][2] + args = mockLog.event.args[0] + t.equal(args.length, 3) + t.equal(args[0], 'device:delete') + t.equal(args[1], mockRequest) + var details = args[2] t.equal(details.uid, uid.toString('hex')) t.equal(details.id, deviceId) t.ok(Date.now() - details.timestamp < 100) @@ -397,12 +440,23 @@ test('/account/create', function (t) { entrypoint: 'preferences', utmContent: 'some-content-string' } + }, + query: { + keys: 'true' } }) + var emailCode = crypto.randomBytes(16) + var keyFetchTokenId = crypto.randomBytes(16) + var sessionTokenId = crypto.randomBytes(16) + var uid = uuid.v4('binary') var mockDB = mocks.mockDB({ email: TEST_EMAIL, + emailCode: emailCode, emailVerified: false, - uid: uuid.v4('binary') + keyFetchTokenId: keyFetchTokenId, + sessionTokenId: sessionTokenId, + uid: uid, + wrapWrapKb: 'wibble' }, { emailRecord: new error.unknownAccount() }) @@ -417,10 +471,31 @@ test('/account/create', function (t) { write: sinon.spy() } }) - mockLog.metricsContext.validate = sinon.spy() + var mockMetricsContext = mocks.mockMetricsContext({ + gather: sinon.spy(function (data, request) { + return P.resolve(request.payload.metricsContext) + }) + }) + mockLog.setMetricsContext(mockMetricsContext) + mockLog.activityEvent = sinon.spy(function () { + return P.resolve() + }) + var mockMailer = mocks.mockMailer() var accountRoutes = makeRoutes({ db: mockDB, - log: mockLog + log: mockLog, + mailer: mockMailer, + metricsContext: mockMetricsContext, + Password: function () { + return { + unwrap: function () { + return P.resolve('wibble') + }, + verifyHash: function () { + return P.resolve('wibble') + } + } + } }) var route = getRoute(accountRoutes, '/account/create') @@ -432,13 +507,42 @@ test('/account/create', function (t) { t.equal(eventData.event, 'login', 'it was a login event') t.equal(eventData.data.service, 'sync', 'it was for sync') t.equal(eventData.data.email, TEST_EMAIL, 'it was for the correct email') - t.equal(eventData.data.metricsContext.entrypoint, 'preferences', 'it contained the entrypoint metrics field') - t.equal(eventData.data.metricsContext.utm_content, 'some-content-string', 'it contained the utm_content metrics field') + t.deepEqual(eventData.data.metricsContext, mockRequest.payload.metricsContext, 'it contained the correct metrics context metadata') - t.equal(mockLog.metricsContext.validate.callCount, 1, 'metricsContext.validate was called') - var call = mockLog.metricsContext.validate.getCall(0) - t.equal(call.args.length, 1, 'validate was called with a single argument') - t.deepEqual(call.args[0], mockRequest, 'validate was called with the request') + t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once') + var args = mockLog.activityEvent.args[0] + t.equal(args.length, 3, 'log.activityEvent was passed three arguments') + t.equal(args[0], 'account.created', 'first argument was event name') + t.equal(args[1], mockRequest, 'second argument was request object') + t.deepEqual(args[2], { uid: uid.toString('hex') }, 'third argument contained uid') + + t.equal(mockMetricsContext.validate.callCount, 1, 'metricsContext.validate was called') + args = mockMetricsContext.validate.args[0] + t.equal(args.length, 1, 'validate was called with a single argument') + t.deepEqual(args[0], mockRequest, 'validate was called with the request') + + t.equal(mockMetricsContext.stash.callCount, 3, 'metricsContext.stash was called three times') + + args = mockMetricsContext.stash.args[0] + t.equal(args.length, 3, 'metricsContext.stash was passed three arguments first time') + t.deepEqual(args[0].tokenId, sessionTokenId, 'first argument was session token') + t.deepEqual(args[0].uid, uid, 'sessionToken.uid was correct') + t.deepEqual(args[1], [ 'device.created', 'account.signed' ], 'second argument was event array') + t.equal(args[2], mockRequest.payload.metricsContext, 'third argument was metrics context') + + args = mockMetricsContext.stash.args[1] + t.equal(args.length, 3, 'metricsContext.stash was passed three arguments second time') + t.equal(args[0].id, emailCode.toString('hex'), 'first argument was synthesized token') + t.deepEqual(args[0].uid, uid, 'token.uid was correct') + t.deepEqual(args[1], 'account.verified', 'second argument was event name') + t.equal(args[2], mockRequest.payload.metricsContext, 'third argument was metrics context') + + args = mockMetricsContext.stash.args[2] + t.equal(args.length, 3, 'metricsContext.stash was passed three arguments third time') + t.deepEqual(args[0].tokenId, keyFetchTokenId, 'first argument was key fetch token') + t.deepEqual(args[0].uid, uid, 'keyFetchToken.uid was correct') + t.deepEqual(args[1], 'account.keyfetch', 'second argument was event name') + t.equal(args[2], mockRequest.payload.metricsContext, 'third argument was metrics context') }).finally(function () { mockLog.close() }) @@ -466,10 +570,14 @@ test('/account/login', function (t) { } } }) + var keyFetchTokenId = crypto.randomBytes(16) + var sessionTokenId = crypto.randomBytes(16) var uid = uuid.v4('binary') var mockDB = mocks.mockDB({ email: TEST_EMAIL, emailVerified: true, + keyFetchTokenId: keyFetchTokenId, + sessionTokenId: sessionTokenId, uid: uid }) // We want to test what's actually written to stdout by the logger. @@ -483,7 +591,15 @@ test('/account/login', function (t) { write: sinon.spy() } }) - mockLog.metricsContext.validate = sinon.spy() + var mockMetricsContext = mocks.mockMetricsContext({ + gather: sinon.spy(function (data, request) { + return P.resolve(request.payload.metricsContext) + }) + }) + mockLog.setMetricsContext(mockMetricsContext) + mockLog.activityEvent = sinon.spy(function () { + return P.resolve() + }) var mockMailer = mocks.mockMailer() var accountRoutes = makeRoutes({ checkPassword: function () { @@ -497,7 +613,8 @@ test('/account/login', function (t) { }, db: mockDB, log: mockLog, - mailer: mockMailer + mailer: mockMailer, + metricsContext: mockMetricsContext }) var route = getRoute(accountRoutes, '/account/login') @@ -512,13 +629,35 @@ test('/account/login', function (t) { t.equal(eventData.event, 'login', 'it was a login event') t.equal(eventData.data.service, 'sync', 'it was for sync') t.equal(eventData.data.email, TEST_EMAIL, 'it was for the correct email') - t.equal(eventData.data.metricsContext.entrypoint, 'preferences', 'it contained the entrypoint metrics field') - t.equal(eventData.data.metricsContext.utm_content, 'some-content-string', 'it contained the utm_content metrics field') + t.deepEqual(eventData.data.metricsContext, mockRequest.payload.metricsContext, 'it contained the metrics context') - t.equal(mockLog.metricsContext.validate.callCount, 1, 'metricsContext.validate was called') - var call = mockLog.metricsContext.validate.getCall(0) - t.equal(call.args.length, 1, 'validate was called with a single argument') - t.deepEqual(call.args[0], mockRequest, 'validate was called with the request') + t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once') + var args = mockLog.activityEvent.args[0] + t.equal(args.length, 3, 'log.activityEvent was passed three arguments') + t.equal(args[0], 'account.login', 'first argument was event name') + t.equal(args[1], mockRequest, 'second argument was request object') + t.deepEqual(args[2], { uid: uid.toString('hex') }, 'third argument contained uid') + + t.equal(mockMetricsContext.validate.callCount, 1, 'metricsContext.validate was called') + args = mockMetricsContext.validate.args[0] + t.equal(args.length, 1, 'validate was called with a single argument') + t.deepEqual(args[0], mockRequest, 'validate was called with the request') + + t.equal(mockMetricsContext.stash.callCount, 2, 'metricsContext.stash was called twice') + + args = mockMetricsContext.stash.args[0] + t.equal(args.length, 3, 'metricsContext.stash was passed three arguments first time') + t.deepEqual(args[0].tokenId, sessionTokenId, 'first argument was session token') + t.deepEqual(args[0].uid, uid, 'sessionToken.uid was correct') + t.deepEqual(args[1], [ 'device.created', 'account.signed' ], 'second argument was event array') + t.equal(args[2], mockRequest.payload.metricsContext, 'third argument was metrics context') + + args = mockMetricsContext.stash.args[1] + t.equal(args.length, 3, 'metricsContext.stash was passed three arguments second time') + t.deepEqual(args[0].tokenId, keyFetchTokenId, 'first argument was key fetch token') + t.deepEqual(args[0].uid, uid, 'keyFetchToken.uid was correct') + t.deepEqual(args[1], 'account.keyfetch', 'second argument was event name') + t.equal(args[2], mockRequest.payload.metricsContext, 'third argument was metrics context') t.equal(mockMailer.sendNewDeviceLoginNotification.callCount, 1, 'mailer.sendNewDeviceLoginNotification was called') t.equal(mockMailer.sendVerifyLoginEmail.callCount, 0, 'mailer.sendVerifyLoginEmail was not called') @@ -696,7 +835,6 @@ test('/account/login', function (t) { }, t) }) - test('/recovery_email/verify_code', function (t) { var uid = uuid.v4('binary').toString('hex') var mockRequest = mocks.mockRequest({ @@ -736,20 +874,91 @@ test('/recovery_email/verify_code', function (t) { t.equal(mockDB.verifyTokens.callCount, 1, 'calls verifyTokens') t.equal(mockDB.verifyEmail.callCount, 1, 'calls verifyEmail') t.equal(mockLog.event.callCount, 1, 'logs verified') + + t.equal(mockLog.activityEvent.callCount, 1, 'activityEvent was called once') + + var args = mockLog.activityEvent.args[0] + t.equal(args.length, 3, 'activityEvent was passed three arguments') + t.equal(args[0], 'account.verified', 'first argument was event name') + t.deepEqual(args[1], { + auth: { + credentials: { + uid: uid, + id: mockRequest.payload.code, + } + }, + headers: mockRequest.headers, + payload: mockRequest.payload, + query: mockRequest.query + }, 'second argument was synthesized request object') + t.deepEqual(args[2], { + uid: uid.toString('hex') + }, 'third argument contained uid') + t.equal(JSON.stringify(response), '{}') }) + .then(function () { + mockLog.activityEvent.reset() + }) }, t) test('verifies account with a reminder payload', function (t) { mockRequest.payload.reminder = 'second' return runTest(route, mockRequest, function (response) { - t.equal(mockLog.activityEvent.callCount, 1, 'calls activityEvent') - var activityCall = mockLog.activityEvent.getCall(0).args - t.equal(activityCall[0], 'account.reminder') - t.equal(activityCall[2].uid, uid) + t.equal(mockLog.activityEvent.callCount, 2, 'activityEvent was called twice') + t.equal(mockLog.activityEvent.args[0][0], 'account.verified', 'first call was account.verified') + + var args = mockLog.activityEvent.args[1] + t.equal(args.length, 3, 'activityEvent was passed three arguments second time') + t.equal(args[0], 'account.reminder', 'first argument was event name') + t.equal(args[1], mockRequest, 'second argument was request object') + t.deepEqual(args[2], { + uid: uid.toString('hex') + }, 'third argument contained uid') + t.equal(JSON.stringify(response), '{}') }) + .then(function () { + mockLog.activityEvent.reset() + }) }, t) }) +test('/account/keys', function (t) { + var keyFetchTokenId = crypto.randomBytes(16) + var uid = uuid.v4('binary') + var mockRequest = mocks.mockRequest({ + credentials: { + emailVerified: true, + id: keyFetchTokenId.toString('hex'), + keyBundle: crypto.randomBytes(16), + tokenId: keyFetchTokenId, + uid: uid + } + }) + var mockDB = mocks.mockDB() + var mockLog = mocks.spyLog() + var accountRoutes = makeRoutes({ + db: mockDB, + log: mockLog + }) + var route = getRoute(accountRoutes, '/account/keys') + + return runTest(route, mockRequest, function (response) { + t.deepEqual(response, { bundle: mockRequest.auth.credentials.keyBundle.toString('hex') }, 'response was correct') + + t.equal(mockDB.deleteKeyFetchToken.callCount, 1, 'db.deleteKeyFetchToken was called once') + var args = mockDB.deleteKeyFetchToken.args[0] + t.equal(args.length, 1, 'db.deleteKeyFetchToken was passed one argument') + t.equal(args[0], mockRequest.auth.credentials, 'db.deleteKeyFetchToken was passed key fetch token') + + t.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once') + args = mockLog.activityEvent.args[0] + t.equal(args.length, 3, 'log.activityEvent was passed three arguments') + t.equal(args[0], 'account.keyfetch', 'first argument was event name') + t.equal(args[1], mockRequest, 'second argument was request object') + t.deepEqual(args[2], { uid: uid.toString('hex') }, 'third argument contained uid') + }) +}) + diff --git a/test/local/log_tests.js b/test/local/log_tests.js index b2edb2e4..14517fb1 100644 --- a/test/local/log_tests.js +++ b/test/local/log_tests.js @@ -6,6 +6,7 @@ var test = require('../ptaptest') var path = require('path') var sinon = require('sinon') var proxyquire = require('proxyquire') +var P = require('../../lib/promise') var logger = { debug: sinon.spy(), @@ -18,12 +19,11 @@ var statsd = { init: sinon.spy(), write: sinon.spy() } -var metricsContext = function () { - return metricsContext +var metricsContext = { + gather: sinon.spy(function (data, request) { + return P.resolve(request.payload && request.payload.metricsContext) + }) } -metricsContext.add = sinon.spy(function (data, context) { - return context -}) var mocks = { mozlog: sinon.spy(function () { return logger @@ -33,8 +33,8 @@ mocks.mozlog.config = sinon.spy() mocks[path.resolve(__dirname, '../../lib') + '/./metrics/statsd'] = function () { return statsd } -mocks[path.resolve(__dirname, '../../lib') + '/./metrics/context'] = metricsContext var log = proxyquire('../../lib/log', mocks)('foo', 'bar') +log.setMetricsContext(metricsContext) test( 'initialised correctly', @@ -55,7 +55,7 @@ test( t.equal(statsd.init.args[0].length, 0, 'statsd.init was passed no arguments') t.equal(statsd.write.callCount, 0, 'statsd.write was not called') - t.equal(metricsContext.add.callCount, 0, 'metricsContext.add was not called') + t.equal(metricsContext.gather.callCount, 0, 'metricsContext.gather was not called') t.equal(logger.debug.callCount, 0, 'logger.debug was not called') t.equal(logger.error.callCount, 0, 'logger.error was not called') t.equal(logger.critical.callCount, 0, 'logger.critical was not called') @@ -81,58 +81,58 @@ test( test( 'log.activityEvent', function (t) { - var payload = { metricsContext: {} } - log.activityEvent('foo', { + var request = { headers: { - 'user-agent': 'bar' + 'user-agent': 'foo' }, - payload: payload - }, { + payload: { + metricsContext: {} + } + } + return log.activityEvent('bar', request, { uid: 'baz' + }).then(function () { + t.equal(metricsContext.gather.callCount, 1, 'metricsContext.gather was called once') + var args = metricsContext.gather.args[0] + t.equal(args.length, 3, 'metricsContext.gather was passed three arguments') + t.equal(typeof args[0], 'object', 'first argument was object') + t.notEqual(args[0], null, 'first argument was not null') + t.equal(Object.keys(args[0]).length, 2, 'first argument had two properties') + t.equal(args[0].event, 'bar', 'event property was correct') + t.equal(args[0].userAgent, 'foo', 'userAgent property was correct') + t.equal(args[1], request, 'second argument was request object') + t.equal(args[2], 'bar', 'third argument was event name') + + t.equal(logger.info.callCount, 1, 'logger.info was called once') + args = logger.info.args[0] + t.equal(args.length, 2, 'logger.info was passed two arguments') + t.equal(args[0], 'activityEvent', 'first argument was correct') + t.equal(typeof args[1], 'object', 'second argument was object') + t.notEqual(args[1], null, 'second argument was not null') + t.equal(Object.keys(args[1]).length, 1, 'second argument had three properties') + t.equal(args[1].uid, 'baz', 'uid property was correct') + + t.equal(statsd.write.callCount, 1, 'statsd.write was called once') + args = statsd.write.args[0] + t.equal(args.length, 1, 'statsd.write was passed one argument') + t.equal(args[0], logger.info.args[0][1], 'statsd.write argument was correct') + + t.equal(logger.debug.callCount, 0, 'logger.debug was not called') + t.equal(logger.error.callCount, 0, 'logger.error was not called') + t.equal(logger.critical.callCount, 0, 'logger.critical was not called') + t.equal(logger.warn.callCount, 0, 'logger.warn was not called') + + metricsContext.gather.reset() + logger.info.reset() + statsd.write.reset() }) - - t.equal(metricsContext.add.callCount, 1, 'metricsContext.add was called once') - var args = metricsContext.add.args[0] - t.equal(args.length, 3, 'metricsContext.add was passed three arguments') - t.equal(typeof args[0], 'object', 'first argument was object') - t.notEqual(args[0], null, 'first argument was not null') - t.equal(Object.keys(args[0]).length, 2, 'first argument had two properties') - t.equal(args[0].event, 'foo', 'event property was correct') - t.equal(args[0].userAgent, 'bar', 'userAgent property was correct') - t.equal(args[1], payload.metricsContext, 'second argument was metricsContext payload') - t.equal(args[2], false, 'third argument was correct') - - t.equal(logger.info.callCount, 1, 'logger.info was called once') - args = logger.info.args[0] - t.equal(args.length, 2, 'logger.info was passed two arguments') - t.equal(args[0], 'activityEvent', 'first argument was correct') - t.equal(typeof args[1], 'object', 'second argument was object') - t.notEqual(args[1], null, 'second argument was not null') - t.equal(Object.keys(args[1]).length, 1, 'second argument had one property') - t.equal(args[1].uid, 'baz', 'uid property was correct') - - t.equal(statsd.write.callCount, 1, 'statsd.write was called once') - args = statsd.write.args[0] - t.equal(args.length, 1, 'statsd.write was passed one argument') - t.equal(args[0], logger.info.args[0][1], 'statsd.write argument was correct') - - t.equal(logger.debug.callCount, 0, 'logger.debug was not called') - t.equal(logger.error.callCount, 0, 'logger.error was not called') - t.equal(logger.critical.callCount, 0, 'logger.critical was not called') - t.equal(logger.warn.callCount, 0, 'logger.warn was not called') - - t.end() - - metricsContext.add.reset() - logger.info.reset() - statsd.write.reset() } ) test( 'log.activityEvent with service payload parameter', function (t) { - log.activityEvent('wibble', { + return log.activityEvent('wibble', { headers: {}, payload: { metricsContext: {}, @@ -140,40 +140,38 @@ test( } }, { uid: 'ugg' + }).then(function () { + t.equal(metricsContext.gather.callCount, 1, 'metricsContext.gather was called once') + var args = metricsContext.gather.args[0] + t.equal(args[0].event, 'wibble', 'event property was correct') + t.equal(args[0].userAgent, undefined, 'userAgent property was undefined') + t.equal(typeof args[1], 'object', 'second argument was object') + t.notEqual(args[1], null, 'second argument was not null') + + t.equal(logger.info.callCount, 1, 'logger.info was called once') + args = logger.info.args[0] + t.equal(Object.keys(args[1]).length, 2, 'second argument had four properties') + t.equal(args[1].service, 'blee', 'service property was correct') + + t.equal(statsd.write.callCount, 1, 'statsd.write was called once') + t.equal(statsd.write.args[0][0], args[1], 'statsd.write argument was correct') + + t.equal(logger.debug.callCount, 0, 'logger.debug was not called') + t.equal(logger.error.callCount, 0, 'logger.error was not called') + t.equal(logger.critical.callCount, 0, 'logger.critical was not called') + t.equal(logger.warn.callCount, 0, 'logger.warn was not called') + + metricsContext.gather.reset() + logger.info.reset() + statsd.write.reset() }) - - t.equal(metricsContext.add.callCount, 1, 'metricsContext.add was called once') - var args = metricsContext.add.args[0] - t.equal(args[0].event, 'wibble', 'event property was correct') - t.equal(args[0].userAgent, undefined, 'userAgent property was undefined') - t.equal(typeof args[1], 'object', 'second argument was object') - t.notEqual(args[1], null, 'second argument was not null') - - t.equal(logger.info.callCount, 1, 'logger.info was called once') - args = logger.info.args[0] - t.equal(Object.keys(args[1]).length, 2, 'second argument had two properties') - t.equal(args[1].service, 'blee', 'service property was correct') - - t.equal(statsd.write.callCount, 1, 'statsd.write was called once') - t.equal(statsd.write.args[0][0], args[1], 'statsd.write argument was correct') - - t.equal(logger.debug.callCount, 0, 'logger.debug was not called') - t.equal(logger.error.callCount, 0, 'logger.error was not called') - t.equal(logger.critical.callCount, 0, 'logger.critical was not called') - t.equal(logger.warn.callCount, 0, 'logger.warn was not called') - - t.end() - - metricsContext.add.reset() - logger.info.reset() - statsd.write.reset() } ) test( 'log.activityEvent with service query parameter', function (t) { - log.activityEvent('foo', { + return log.activityEvent('foo', { headers: {}, payload: { metricsContext: {} @@ -183,34 +181,32 @@ test( } }, { uid: 'baz' + }).then(function () { + t.equal(metricsContext.gather.callCount, 1, 'metricsContext.gather was called once') + t.equal(metricsContext.gather.args[0][0].event, 'foo', 'event property was correct') + + t.equal(logger.info.callCount, 1, 'logger.info was called once') + t.equal(logger.info.args[0][1].service, 'bar', 'service property was correct') + + t.equal(statsd.write.callCount, 1, 'statsd.write was called once') + t.equal(statsd.write.args[0][0], logger.info.args[0][1], 'statsd.write argument was correct') + + t.equal(logger.debug.callCount, 0, 'logger.debug was not called') + t.equal(logger.error.callCount, 0, 'logger.error was not called') + t.equal(logger.critical.callCount, 0, 'logger.critical was not called') + t.equal(logger.warn.callCount, 0, 'logger.warn was not called') + + metricsContext.gather.reset() + logger.info.reset() + statsd.write.reset() }) - - t.equal(metricsContext.add.callCount, 1, 'metricsContext.add was called once') - t.equal(metricsContext.add.args[0][0].event, 'foo', 'event property was correct') - - t.equal(logger.info.callCount, 1, 'logger.info was called once') - t.equal(logger.info.args[0][1].service, 'bar', 'service property was correct') - - t.equal(statsd.write.callCount, 1, 'statsd.write was called once') - t.equal(statsd.write.args[0][0], logger.info.args[0][1], 'statsd.write argument was correct') - - t.equal(logger.debug.callCount, 0, 'logger.debug was not called') - t.equal(logger.error.callCount, 0, 'logger.error was not called') - t.equal(logger.critical.callCount, 0, 'logger.critical was not called') - t.equal(logger.warn.callCount, 0, 'logger.warn was not called') - - t.end() - - metricsContext.add.reset() - logger.info.reset() - statsd.write.reset() } ) test( 'log.activityEvent with service metricsContext property and service payload parameter', function (t) { - log.activityEvent('foo', { + return log.activityEvent('foo', { headers: {}, payload: { metricsContext: { @@ -220,33 +216,31 @@ test( } }, { uid: 'qux' + }).then(function () { + t.equal(metricsContext.gather.callCount, 1, 'metricsContext.gather was called once') + + t.equal(logger.info.callCount, 1, 'logger.info was called once') + t.equal(logger.info.args[0][1].service, 'bar', 'service property was correct') + + t.equal(statsd.write.callCount, 1, 'statsd.write was called once') + t.equal(statsd.write.args[0][0], logger.info.args[0][1], 'statsd.write argument was correct') + + t.equal(logger.debug.callCount, 0, 'logger.debug was not called') + t.equal(logger.error.callCount, 0, 'logger.error was not called') + t.equal(logger.critical.callCount, 0, 'logger.critical was not called') + t.equal(logger.warn.callCount, 0, 'logger.warn was not called') + + metricsContext.gather.reset() + logger.info.reset() + statsd.write.reset() }) - - t.equal(metricsContext.add.callCount, 1, 'metricsContext.add was called once') - - t.equal(logger.info.callCount, 1, 'logger.info was called once') - t.equal(logger.info.args[0][1].service, 'bar', 'service property was correct') - - t.equal(statsd.write.callCount, 1, 'statsd.write was called once') - t.equal(statsd.write.args[0][0], logger.info.args[0][1], 'statsd.write argument was correct') - - t.equal(logger.debug.callCount, 0, 'logger.debug was not called') - t.equal(logger.error.callCount, 0, 'logger.error was not called') - t.equal(logger.critical.callCount, 0, 'logger.critical was not called') - t.equal(logger.warn.callCount, 0, 'logger.warn was not called') - - t.end() - - metricsContext.add.reset() - logger.info.reset() - statsd.write.reset() } ) test( 'log.activityEvent with extra data', function (t) { - log.activityEvent('foo', { + return log.activityEvent('foo', { headers: { 'user-agent': 'bar' }, @@ -257,124 +251,84 @@ test( baz: 'qux', uid: 42, wibble: 'blee' + }).then(function () { + t.equal(metricsContext.gather.callCount, 1, 'metricsContext.gather was called once') + t.equal(Object.keys(metricsContext.gather.args[0][0]).length, 2, 'first argument had two properties') + + t.equal(logger.info.callCount, 1, 'logger.info was called once') + var args = logger.info.args[0] + t.equal(Object.keys(args[1]).length, 3, 'second argument had three properties') + t.equal(args[1].baz, 'qux', 'first extra data property was correct') + t.equal(args[1].wibble, 'blee', 'second extra data property was correct') + + t.equal(statsd.write.callCount, 1, 'statsd.write was called once') + t.equal(statsd.write.args[0][0], args[1], 'statsd.write argument was correct') + + t.equal(logger.debug.callCount, 0, 'logger.debug was not called') + t.equal(logger.error.callCount, 0, 'logger.error was not called') + t.equal(logger.critical.callCount, 0, 'logger.critical was not called') + t.equal(logger.warn.callCount, 0, 'logger.warn was not called') + + metricsContext.gather.reset() + logger.info.reset() + statsd.write.reset() }) - - t.equal(metricsContext.add.callCount, 1, 'metricsContext.add was called once') - t.equal(Object.keys(metricsContext.add.args[0][0]).length, 2, 'first argument had two properties') - - t.equal(logger.info.callCount, 1, 'logger.info was called once') - var args = logger.info.args[0] - t.equal(Object.keys(args[1]).length, 3, 'second argument had three properties') - t.equal(args[1].baz, 'qux', 'first extra data property was correct') - t.equal(args[1].wibble, 'blee', 'second extra data property was correct') - - t.equal(statsd.write.callCount, 1, 'statsd.write was called once') - t.equal(statsd.write.args[0][0], args[1], 'statsd.write argument was correct') - - t.equal(logger.debug.callCount, 0, 'logger.debug was not called') - t.equal(logger.error.callCount, 0, 'logger.error was not called') - t.equal(logger.critical.callCount, 0, 'logger.critical was not called') - t.equal(logger.warn.callCount, 0, 'logger.warn was not called') - - t.end() - - metricsContext.add.reset() - logger.info.reset() - statsd.write.reset() - } -) - -test( - 'log.activityEvent with DNT header', - function (t) { - log.activityEvent('foo', { - headers: { - 'dnt': '1' - }, - payload: { - metricsContext: {} - } - }, { - uid: 42 - }) - - t.equal(metricsContext.add.callCount, 1, 'metricsContext.add was called once') - t.equal(metricsContext.add.args[0][2], true, 'third argument was correct') - - t.equal(logger.info.callCount, 1, 'logger.info was called once') - - t.equal(statsd.write.callCount, 1, 'statsd.write was called once') - - t.equal(logger.debug.callCount, 0, 'logger.debug was not called') - t.equal(logger.error.callCount, 0, 'logger.error was not called') - t.equal(logger.critical.callCount, 0, 'logger.critical was not called') - t.equal(logger.warn.callCount, 0, 'logger.warn was not called') - - t.end() - - metricsContext.add.reset() - logger.info.reset() - statsd.write.reset() } ) test( 'log.activityEvent with no data', function (t) { - log.activityEvent('foo', { + return log.activityEvent('foo', { headers: {}, payload: { metricsContext: {} } + }).then(function () { + t.equal(logger.error.callCount, 1, 'logger.error was called once') + var args = logger.error.args[0] + t.equal(args.length, 2, 'logger.error was passed two arguments') + t.equal(args[0], 'log.activityEvent', 'first argument was correct') + t.equal(Object.keys(args[1]).length, 2, 'second argument had two properties') + t.equal(args[1].data, undefined, 'data property was undefined') + + t.equal(metricsContext.gather.callCount, 0, 'metricsContext.gather was not called') + t.equal(statsd.write.callCount, 0, 'statsd.write was not called') + t.equal(logger.debug.callCount, 0, 'logger.debug was not called') + t.equal(logger.critical.callCount, 0, 'logger.critical was not called') + t.equal(logger.warn.callCount, 0, 'logger.warn was not called') + t.equal(logger.info.callCount, 0, 'logger.info was not called') + + logger.error.reset() }) - - t.equal(logger.error.callCount, 1, 'logger.error was called once') - var args = logger.error.args[0] - t.equal(args.length, 2, 'logger.error was passed two arguments') - t.equal(args[0], 'log.activityEvent', 'first argument was correct') - t.equal(Object.keys(args[1]).length, 2, 'second argument had two properties') - t.equal(args[1].data, undefined, 'data property was undefined') - - t.equal(metricsContext.add.callCount, 0, 'metricsContext.add was not called') - t.equal(statsd.write.callCount, 0, 'statsd.write was not called') - t.equal(logger.debug.callCount, 0, 'logger.debug was not called') - t.equal(logger.critical.callCount, 0, 'logger.critical was not called') - t.equal(logger.warn.callCount, 0, 'logger.warn was not called') - t.equal(logger.info.callCount, 0, 'logger.info was not called') - - t.end() - - logger.error.reset() } ) test( 'log.activityEvent with no uid', function (t) { - log.activityEvent('foo', { + return log.activityEvent('foo', { headers: {}, payload: { metricsContext: {} } }, { foo: 'bar' + }).then(function () { + t.equal(logger.error.callCount, 1, 'logger.error was called once') + var args = logger.error.args[0] + t.equal(Object.keys(args[1].data).length, 1, 'data property had one property') + t.equal(args[1].data.foo, 'bar', 'data property had correct property') + + t.equal(metricsContext.gather.callCount, 0, 'metricsContext.gather was not called') + t.equal(statsd.write.callCount, 0, 'statsd.write was not called') + t.equal(logger.debug.callCount, 0, 'logger.debug was not called') + t.equal(logger.critical.callCount, 0, 'logger.critical was not called') + t.equal(logger.warn.callCount, 0, 'logger.warn was not called') + t.equal(logger.info.callCount, 0, 'logger.info was not called') + + logger.error.reset() }) - - t.equal(logger.error.callCount, 1, 'logger.error was called once') - var args = logger.error.args[0] - t.equal(Object.keys(args[1].data).length, 1, 'data property had one property') - t.equal(args[1].data.foo, 'bar', 'data property had correct property') - - t.equal(metricsContext.add.callCount, 0, 'metricsContext.add was not called') - t.equal(statsd.write.callCount, 0, 'statsd.write was not called') - t.equal(logger.debug.callCount, 0, 'logger.debug was not called') - t.equal(logger.critical.callCount, 0, 'logger.critical was not called') - t.equal(logger.warn.callCount, 0, 'logger.warn was not called') - t.equal(logger.info.callCount, 0, 'logger.info was not called') - - t.end() - - logger.error.reset() } ) diff --git a/test/local/metrics_context_tests.js b/test/local/metrics_context_tests.js index dbbcb270..30982ed9 100644 --- a/test/local/metrics_context_tests.js +++ b/test/local/metrics_context_tests.js @@ -7,168 +7,589 @@ var sinon = require('sinon') var test = require('../ptaptest') var mocks = require('../mocks') - -var metricsContext = require('../../lib/metrics/context')(mocks.mockLog(), {}) +var log = mocks.spyLog() +var Memcached = require('memcached') +var metricsContext = require('../../lib/metrics/context')(log, { + memcached: { + address: '127.0.0.1:1121', + idle: 500, + lifetime: 30 + } +}) +var P = require('../../lib/promise') test( 'metricsContext interface is correct', function (t) { t.equal(typeof metricsContext, 'object', 'metricsContext is object') t.notEqual(metricsContext, null, 'metricsContext is not null') - t.equal(Object.keys(metricsContext).length, 3, 'metricsContext has 3 properties') + t.equal(Object.keys(metricsContext).length, 4, 'metricsContext has 4 properties') t.equal(typeof metricsContext.schema, 'object', 'metricsContext.schema is object') t.notEqual(metricsContext.schema, null, 'metricsContext.schema is not null') - t.equal(typeof metricsContext.add, 'function', 'metricsContext.add is function') - t.equal(metricsContext.add.length, 3, 'metricsContext.add expects 3 arguments') + t.equal(typeof metricsContext.stash, 'function', 'metricsContext.stash is function') + t.equal(metricsContext.stash.length, 3, 'metricsContext.stash expects 3 arguments') + + t.equal(typeof metricsContext.gather, 'function', 'metricsContext.gather is function') + t.equal(metricsContext.gather.length, 3, 'metricsContext.gather expects 3 arguments') + + t.equal(typeof metricsContext.validate, 'function', 'metricsContext.validate is function') + t.equal(metricsContext.validate.length, 1, 'metricsContext.validate expects 1 argument') t.end() } ) test( - 'metricsContext.add without metadata', + 'metricsContext.stash', function (t) { - var result = metricsContext.add({}) - - t.equal(typeof result, 'object', 'result is object') - t.notEqual(result, null, 'result is not null') - t.equal(Object.keys(result).length, 0, 'result is empty') - - t.end() - } -) - -test( - 'metricsContext.add with metadata', - function (t) { - var time = Date.now() - 1 - var result = metricsContext.add({}, { - flowId: 'mock flow id', - flowBeginTime: time, - context: 'mock context', - entrypoint: 'mock entry point', - migration: 'mock migration', - service: 'mock service', - utmCampaign: 'mock utm_campaign', - utmContent: 'mock utm_content', - utmMedium: 'mock utm_medium', - utmSource: 'mock utm_source', - utmTerm: 'mock utm_term', - ignore: 'mock ignorable property' + sinon.stub(Memcached.prototype, 'setAsync', function () { + return P.resolve('wibble') }) + metricsContext.stash({ + uid: 'foo', + id: 'bar' + }, 'baz', 'qux').then(function (result) { + t.deepEqual(result, [ 'wibble' ], 'result is correct') - t.equal(typeof result, 'object', 'result is object') - t.notEqual(result, null, 'result is not null') - t.equal(Object.keys(result).length, 12, 'result has 12 properties') - t.ok(result.time > time, 'result.time seems correct') - t.equal(result.flow_id, 'mock flow id', 'result.flow_id is correct') - t.ok(result.flow_time > 0, 'result.flow_time is greater than zero') - t.ok(result.flow_time < time, 'result.flow_time is less than the current time') - t.equal(result.context, 'mock context', 'result.context is correct') - t.equal(result.entrypoint, 'mock entry point', 'result.entrypoint is correct') - t.equal(result.migration, 'mock migration', 'result.migration is correct') - t.equal(result.service, 'mock service', 'result.service is correct') - t.equal(result.utm_campaign, 'mock utm_campaign', 'result.utm_campaign is correct') - t.equal(result.utm_content, 'mock utm_content', 'result.utm_content is correct') - t.equal(result.utm_medium, 'mock utm_medium', 'result.utm_medium is correct') - t.equal(result.utm_source, 'mock utm_source', 'result.utm_source is correct') - t.equal(result.utm_term, 'mock utm_term', 'result.utm_term is correct') + t.equal(Memcached.prototype.setAsync.callCount, 1, 'memcached.setAsync was called once') + t.equal(Memcached.prototype.setAsync.args[0].length, 3, 'memcached.setAsync was passed three arguments') + t.equal(Memcached.prototype.setAsync.args[0][0], 'foo:bar:baz', 'first argument was correct') + t.equal(Memcached.prototype.setAsync.args[0][1], 'qux', 'second argument was correct') + t.equal(Memcached.prototype.setAsync.args[0][2], 30, 'third argument was correct') - t.end() - } -) + t.equal(log.error.callCount, 0, 'log.error was not called') -test( - 'metricsContext.add with bad flowBeginTime', - function (t) { - var result = metricsContext.add({}, { - flowBeginTime: Date.now() + 10000 + Memcached.prototype.setAsync.restore() + + t.end() }) - - t.equal(typeof result, 'object', 'result is object') - t.notEqual(result, null, 'result is not null') - t.strictEqual(result.flow_time, 0, 'result.time is zero') - - t.end() } ) test( - 'metricsContext.add with DNT header', + 'metricsContext.stash with two events', function (t) { + sinon.stub(Memcached.prototype, 'setAsync', function () { + return P.resolve('wibble') + }) + metricsContext.stash({ + uid: 'foo', + id: 'bar' + }, [ 'baz', 'qux' ], 'blee').then(function (result) { + t.deepEqual(result, [ 'wibble', 'wibble' ], 'result is correct') + + t.equal(Memcached.prototype.setAsync.callCount, 2, 'memcached.setAsync was called twice') + t.equal(Memcached.prototype.setAsync.args[0][0], 'foo:bar:baz', 'first argument was correct in first call') + t.equal(Memcached.prototype.setAsync.args[0][1], 'blee', 'second argument was correct in first call') + t.equal(Memcached.prototype.setAsync.args[0][2], 30, 'third argument was correct in first call') + t.equal(Memcached.prototype.setAsync.args[1][0], 'foo:bar:qux', 'first argument was correct in second call') + t.equal(Memcached.prototype.setAsync.args[1][1], 'blee', 'second argument was correct in second call') + t.equal(Memcached.prototype.setAsync.args[1][2], 30, 'third argument was correct in second call') + + t.equal(log.error.callCount, 0, 'log.error was not called') + + Memcached.prototype.setAsync.restore() + + t.end() + }) + } +) + +test( + 'metricsContext.stash error', + function (t) { + sinon.stub(Memcached.prototype, 'setAsync', function () { + return P.reject('wibble') + }) + metricsContext.stash({ + uid: 'foo', + id: 'bar' + }, 'baz', 'qux').then(function (result) { + t.deepEqual(result, [ undefined ], 'result is undefined') + + t.equal(Memcached.prototype.setAsync.callCount, 1, 'memcached.setAsync was called once') + + t.equal(log.error.callCount, 1, 'log.error was called once') + t.equal(log.error.args[0].length, 1, 'log.error was passed one argument') + t.equal(log.error.args[0][0].op, 'metricsContext.stash', 'argument op property was correct') + t.equal(log.error.args[0][0].err, 'wibble', 'argument err property was correct') + + Memcached.prototype.setAsync.restore() + log.error.reset() + + t.end() + }) + } +) + +test( + 'metricsContext.stash without token', + function (t) { + sinon.stub(Memcached.prototype, 'setAsync', function () { + return P.resolve('wibble') + }) + metricsContext.stash(null, 'foo', 'bar').then(function (result) { + t.equal(result, undefined, 'result is undefined') + + t.equal(log.error.callCount, 1, 'log.error was called once') + t.equal(log.error.args[0].length, 1, 'log.error was passed one argument') + t.equal(log.error.args[0][0].op, 'metricsContext.stash', 'op property was correct') + t.equal(log.error.args[0][0].err.message, 'Invalid argument', 'err.message property was correct') + t.equal(log.error.args[0][0].token, null, 'token property was correct') + t.deepEqual(log.error.args[0][0].events, ['foo'], 'events property was correct') + + t.equal(Memcached.prototype.setAsync.callCount, 0, 'memcached.setAsync was not called') + + Memcached.prototype.setAsync.restore() + log.error.reset() + + t.end() + }) + } +) + +test( + 'metricsContext.stash without event', + function (t) { + sinon.stub(Memcached.prototype, 'setAsync', function () { + return P.resolve('wibble') + }) + metricsContext.stash({ + uid: 'foo', + id: 'bar' + }, '', 'baz').then(function (result) { + t.equal(result, undefined, 'result is undefined') + + t.equal(log.error.callCount, 1, 'log.error was called once') + t.equal(log.error.args[0].length, 1, 'log.error was passed one argument') + t.equal(log.error.args[0][0].op, 'metricsContext.stash', 'op property was correct') + t.equal(log.error.args[0][0].err.message, 'Invalid argument', 'err.message property was correct') + t.equal(log.error.args[0][0].token.uid, 'foo', 'token.uid property was correct') + t.equal(log.error.args[0][0].token.id, 'bar', 'token.id property was correct') + t.equal(log.error.args[0][0].events, '', 'events property was correct') + + t.equal(Memcached.prototype.setAsync.callCount, 0, 'memcached.setAsync was not called') + + Memcached.prototype.setAsync.restore() + log.error.reset() + + t.end() + }) + } +) + +test( + 'metricsContext.stash without metadata', + function (t) { + sinon.stub(Memcached.prototype, 'setAsync', function () { + return P.resolve('wibble') + }) + metricsContext.stash({ + uid: 'foo', + id: 'bar' + }, 'baz').then(function (result) { + t.equal(result, undefined, 'result is undefined') + + t.equal(Memcached.prototype.setAsync.callCount, 0, 'memcached.setAsync was not called') + t.equal(log.error.callCount, 0, 'log.error was not called') + + Memcached.prototype.setAsync.restore() + + t.end() + }) + } +) + +test( + 'metricsContext.gather without metadata or session token', + function (t) { + metricsContext.gather({}, {}).then(function (result) { + t.equal(typeof result, 'object', 'result is object') + t.notEqual(result, null, 'result is not null') + t.equal(Object.keys(result).length, 0, 'result is empty') + + t.equal(log.error.callCount, 0, 'log.error was not called') + + t.end() + }) + } +) + +test( + 'metricsContext.gather with metadata', + function (t) { + sinon.stub(Memcached.prototype, 'getAsync', function () { + return P.resolve({ + flowId: 'not this flow id', + flowBeginTime: 0 + }) + }) + sinon.stub(Memcached.prototype, 'delAsync', function () { + return P.resolve() + }) var time = Date.now() - 1 - var result = metricsContext.add({}, { - flowId: 'mock flow id', - flowBeginTime: time, - context: 'mock context', - entrypoint: 'mock entry point', - migration: 'mock migration', - service: 'mock service', - utmCampaign: 'mock utm_campaign', - utmContent: 'mock utm_content', - utmMedium: 'mock utm_medium', - utmSource: 'mock utm_source', - utmTerm: 'mock utm_term', - ignore: 'mock ignorable property' - }, true) - - t.equal(Object.keys(result).length, 7, 'result has 7 properties') - t.equal(result.utm_campaign, undefined, 'result.utm_campaign is undefined') - t.equal(result.utm_content, undefined, 'result.utm_content is undefined') - t.equal(result.utm_medium, undefined, 'result.utm_medium is undefined') - t.equal(result.utm_source, undefined, 'result.utm_source is undefined') - t.equal(result.utm_term, undefined, 'result.utm_term is undefined') - - t.end() - } -) - -test( - 'metricsContext.validate with known good data', - function (t) { - var expectedTime = 1451566800000 - var expectedSalt = '4d6f7a696c6c6146697265666f782121' - var expectedHmac = 'c89d56556d22039fbbf54d34e0baf206' - var mockLog = mocks.spyLog() - var mockConfig = { - metrics: { - flow_id_expiry: 60000, - flow_id_key: 'S3CR37' + metricsContext.gather({}, { + payload: { + metricsContext: { + flowId: 'mock flow id', + flowBeginTime: time, + context: 'mock context', + entrypoint: 'mock entry point', + migration: 'mock migration', + service: 'mock service', + utmCampaign: 'mock utm_campaign', + utmContent: 'mock utm_content', + utmMedium: 'mock utm_medium', + utmSource: 'mock utm_source', + utmTerm: 'mock utm_term', + ignore: 'mock ignorable property' + } } - } - var mockRequest = { + }).then(function (result) { + t.equal(typeof result, 'object', 'result is object') + t.notEqual(result, null, 'result is not null') + t.equal(Object.keys(result).length, 12, 'result has 12 properties') + t.ok(result.time > time, 'result.time seems correct') + t.equal(result.flow_id, 'mock flow id', 'result.flow_id is correct') + t.ok(result.flow_time > 0, 'result.flow_time is greater than zero') + t.ok(result.flow_time < time, 'result.flow_time is less than the current time') + t.equal(result.context, 'mock context', 'result.context is correct') + t.equal(result.entrypoint, 'mock entry point', 'result.entrypoint is correct') + t.equal(result.migration, 'mock migration', 'result.migration is correct') + t.equal(result.service, 'mock service', 'result.service is correct') + t.equal(result.utm_campaign, 'mock utm_campaign', 'result.utm_campaign is correct') + t.equal(result.utm_content, 'mock utm_content', 'result.utm_content is correct') + t.equal(result.utm_medium, 'mock utm_medium', 'result.utm_medium is correct') + t.equal(result.utm_source, 'mock utm_source', 'result.utm_source is correct') + t.equal(result.utm_term, 'mock utm_term', 'result.utm_term is correct') + + t.equal(Memcached.prototype.getAsync.callCount, 0, 'memcached.getAsync was not called') + t.equal(Memcached.prototype.delAsync.callCount, 0, 'memcached.delAsync was not called') + t.equal(log.error.callCount, 0, 'log.error was not called') + + Memcached.prototype.getAsync.restore() + Memcached.prototype.delAsync.restore() + + t.end() + }) + } +) + +test( + 'metricsContext.gather with bad flowBeginTime', + function (t) { + metricsContext.gather({}, { + payload: { + metricsContext: { + flowBeginTime: Date.now() + 10000 + } + } + }).then(function (result) { + t.equal(typeof result, 'object', 'result is object') + t.notEqual(result, null, 'result is not null') + t.strictEqual(result.flow_time, 0, 'result.time is zero') + + t.equal(log.error.callCount, 0, 'log.error was not called') + + t.end() + }) + } +) + +test( + 'metricsContext.gather with DNT header', + function (t) { + var time = Date.now() - 1 + metricsContext.gather({}, { headers: { - 'user-agent': 'Firefox' + dnt: '1' }, payload: { metricsContext: { - flowId: expectedSalt + expectedHmac, - flowBeginTime: expectedTime + flowId: 'mock flow id', + flowBeginTime: time, + context: 'mock context', + entrypoint: 'mock entry point', + migration: 'mock migration', + service: 'mock service', + utmCampaign: 'mock utm_campaign', + utmContent: 'mock utm_content', + utmMedium: 'mock utm_medium', + utmSource: 'mock utm_source', + utmTerm: 'mock utm_term', + ignore: 'mock ignorable property' } } - } - sinon.stub(Date, 'now', function() { - return expectedTime + 20000 + }).then(function (result) { + t.equal(Object.keys(result).length, 7, 'result has 7 properties') + t.equal(result.utm_campaign, undefined, 'result.utm_campaign is undefined') + t.equal(result.utm_content, undefined, 'result.utm_content is undefined') + t.equal(result.utm_medium, undefined, 'result.utm_medium is undefined') + t.equal(result.utm_source, undefined, 'result.utm_source is undefined') + t.equal(result.utm_term, undefined, 'result.utm_term is undefined') + + t.equal(log.error.callCount, 0, 'log.error was not called') + + t.end() }) + } +) - try { - var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig) - var valid = metricsContext.validate(mockRequest) - } finally { - Date.now.restore() - } +test( + 'metricsContext.gather with session token', + function (t) { + var time = Date.now() - 1 + sinon.stub(Memcached.prototype, 'getAsync', function () { + return P.resolve({ + flowId: 'flowId', + flowBeginTime: time, + context: 'context', + entrypoint: 'entrypoint', + migration: 'migration', + service: 'service', + utmCampaign: 'utm_campaign', + utmContent: 'utm_content', + utmMedium: 'utm_medium', + utmSource: 'utm_source', + utmTerm: 'utm_term', + ignore: 'ignore me' + }) + }) + sinon.stub(Memcached.prototype, 'delAsync', function () { + return P.resolve() + }) + metricsContext.gather({}, { + auth: { + credentials: { + uid: 'foo', + id: 'bar' + } + } + }, 'baz').then(function (result) { + t.equal(Memcached.prototype.getAsync.callCount, 1, 'memcached.getAsync was called once') + t.equal(Memcached.prototype.getAsync.args[0].length, 1, 'memcached.getAsync was passed one argument') + t.equal(Memcached.prototype.getAsync.args[0][0], 'foo:bar:baz', 'memcached.getAsync argument was correct') - t.ok(valid, 'the known good data is treated as valid') - t.equal(mockLog.warn.callCount, 0, 'log.warn was not called') - t.equal(mockLog.info.callCount, 1, 'log.info was called once') - t.ok(mockLog.info.calledWithExactly({ - op: 'metrics.context.validate', - valid: true, - agent: 'Firefox' - }), 'log.info was called with the expected log data') - t.end() + t.equal(Memcached.prototype.delAsync.callCount, 1, 'memcached.delAsync was called once') + t.equal(Memcached.prototype.delAsync.args[0].length, 1, 'memcached.delAsync was passed one argument') + t.equal(Memcached.prototype.delAsync.args[0][0], 'foo:bar:baz', 'memcached.delAsync argument was correct') + + t.equal(typeof result, 'object', 'result is object') + t.notEqual(result, null, 'result is not null') + t.equal(Object.keys(result).length, 12, 'result has 12 properties') + t.ok(result.time > time, 'result.time seems correct') + t.equal(result.flow_id, 'flowId', 'result.flow_id is correct') + t.ok(result.flow_time > 0, 'result.flow_time is greater than zero') + t.ok(result.flow_time < time, 'result.flow_time is less than the current time') + t.equal(result.context, 'context', 'result.context is correct') + t.equal(result.entrypoint, 'entrypoint', 'result.entry point is correct') + t.equal(result.migration, 'migration', 'result.migration is correct') + t.equal(result.service, 'service', 'result.service is correct') + t.equal(result.utm_campaign, 'utm_campaign', 'result.utm_campaign is correct') + t.equal(result.utm_content, 'utm_content', 'result.utm_content is correct') + t.equal(result.utm_medium, 'utm_medium', 'result.utm_medium is correct') + t.equal(result.utm_source, 'utm_source', 'result.utm_source is correct') + t.equal(result.utm_term, 'utm_term', 'result.utm_term is correct') + + t.equal(log.error.callCount, 0, 'log.error was not called') + + Memcached.prototype.getAsync.restore() + Memcached.prototype.delAsync.restore() + + t.end() + }) + } +) + +test( + 'metricsContext.gather with metadata and session token', + function (t) { + var time = Date.now() - 1 + sinon.stub(Memcached.prototype, 'getAsync', function () { + return P.resolve({ + flowId: 'foo', + flowBeginTime: time + }) + }) + sinon.stub(Memcached.prototype, 'delAsync', function () { + return P.resolve() + }) + metricsContext.gather({}, { + auth: { + credentials: { + uid: 'bar', + id: 'baz' + } + }, + payload: { + metricsContext: { + flowId: 'qux', + flowBeginTime: time + } + } + }, 'blee').then(function (result) { + t.equal(typeof result, 'object', 'result is object') + t.notEqual(result, null, 'result is not null') + t.equal(result.flow_id, 'qux', 'result.flow_id is correct') + + t.equal(Memcached.prototype.delAsync.callCount, 1, 'memcached.delAsync was called once') + t.equal(Memcached.prototype.delAsync.args[0].length, 1, 'memcached.delAsync was called once') + t.equal(Memcached.prototype.delAsync.args[0][0], 'bar:baz:blee', 'memcached.delAsync argument was correct') + + t.equal(Memcached.prototype.getAsync.callCount, 0, 'memcached.getAsync was not called') + t.equal(log.error.callCount, 0, 'log.error was not called') + + Memcached.prototype.getAsync.restore() + Memcached.prototype.delAsync.restore() + + t.end() + }) + } +) + +test( + 'metricsContext.gather with get error', + function (t) { + sinon.stub(Memcached.prototype, 'getAsync', function () { + return P.reject('foo') + }) + sinon.stub(Memcached.prototype, 'delAsync', function () { + return P.resolve() + }) + metricsContext.gather({}, { + auth: { + credentials: { + uid: 'bar', + id: 'baz' + } + } + }, 'qux').then(function () { + t.equal(log.error.callCount, 1, 'log.error was called once') + t.equal(log.error.args[0].length, 1, 'log.error was passed one argument') + t.equal(log.error.args[0][0].op, 'memcached.get', 'argument op property was correct') + t.equal(log.error.args[0][0].err, 'foo', 'argument err property was correct') + + t.equal(Memcached.prototype.getAsync.callCount, 1, 'memcached.getAsync was called once') + t.equal(Memcached.prototype.delAsync.callCount, 1, 'memcached.delAsync was called once') + + Memcached.prototype.getAsync.restore() + Memcached.prototype.delAsync.restore() + log.error.reset() + + t.end() + }) + } +) + +test( + 'metricsContext.gather with del error', + function (t) { + sinon.stub(Memcached.prototype, 'getAsync', function () { + return P.resolve({ + flowId: 'foo', + flowBeginTime: 42 + }) + }) + sinon.stub(Memcached.prototype, 'delAsync', function () { + return P.reject('bar') + }) + metricsContext.gather({}, { + auth: { + credentials: { + uid: 'baz', + id: 'qux' + } + } + }, 'blee').then(function (result) { + t.equal(typeof result, 'object', 'result is object') + t.notEqual(result, null, 'result is not null') + t.equal(result.flow_id, 'foo', 'result.flow_id is correct') + + t.equal(log.error.callCount, 1, 'log.error was called once') + t.equal(log.error.args[0].length, 1, 'log.error was passed one argument') + t.equal(log.error.args[0][0].op, 'memcached.del', 'argument op property was correct') + t.equal(log.error.args[0][0].err, 'bar', 'argument err property was correct') + + t.equal(Memcached.prototype.getAsync.callCount, 1, 'memcached.getAsync was called once') + t.equal(Memcached.prototype.delAsync.callCount, 1, 'memcached.delAsync was called once') + + Memcached.prototype.getAsync.restore() + Memcached.prototype.delAsync.restore() + log.error.reset() + + t.end() + }) + } +) + +test( + 'metricsContext.stash with config.memcached.address === "none"', + function (t) { + var metricsContextWithoutMemcached = require('../../lib/metrics/context')(log, { + memcached: { + address: 'none', + idle: 500, + lifetime: 30 + } + }) + sinon.stub(Memcached.prototype, 'setAsync', function () { + return P.reject('wibble') + }) + metricsContextWithoutMemcached.stash({ + uid: 'foo', + id: 'bar' + }, 'baz', 'qux').then(function (result) { + t.deepEqual(result, [ undefined ], 'result is undefined') + + t.equal(Memcached.prototype.setAsync.callCount, 0, 'memcached.setAsync was not called') + t.equal(log.error.callCount, 0, 'log.error was not called') + + Memcached.prototype.setAsync.restore() + + t.end() + }) + } +) + +test( + 'metricsContext.gather with config.memcached.address === "none"', + function (t) { + var metricsContextWithoutMemcached = require('../../lib/metrics/context')(log, { + memcached: { + address: 'none', + idle: 500, + lifetime: 30 + } + }) + sinon.stub(Memcached.prototype, 'getAsync', function () { + return P.resolve({ + flowId: 'foo', + flowBeginTime: 42 + }) + }) + sinon.stub(Memcached.prototype, 'delAsync', function () { + return P.resolve() + }) + metricsContextWithoutMemcached.gather({}, { + auth: { + credentials: { + uid: 'bar', + id: 'baz' + } + } + }, 'qux').then(function () { + t.equal(Memcached.prototype.getAsync.callCount, 0, 'memcached.getAsync was not called') + t.equal(Memcached.prototype.delAsync.callCount, 0, 'memcached.getAsync was not called') + t.equal(log.error.callCount, 0, 'log.error was not called') + + Memcached.prototype.getAsync.restore() + Memcached.prototype.delAsync.restore() + log.error.reset() + + t.end() + }) } ) diff --git a/test/local/sign_routes.js b/test/local/sign_routes.js new file mode 100644 index 00000000..19de673a --- /dev/null +++ b/test/local/sign_routes.js @@ -0,0 +1,103 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +require('ass') + +var crypto = require('crypto') +var error = require('../../lib/error') +var getRoute = require('../routes_helpers').getRoute +var isA = require('joi') +var mocks = require('../mocks') +var P = require('../../lib/promise') +var sinon = require('sinon') +var test = require('../ptaptest') + +test( + '/certificate/sign emits account.signed activity event', + function (t) { + var mockLog = mocks.mockLog({ + activityEvent: sinon.spy() + }) + var mockRequest = { + auth: { + credentials: { + accountCreatedAt: Date.now(), + deviceId: crypto.randomBytes(16), + emailVerified: true, + lastAuthAt: function () { + return Date.now() + }, + locale: 'en', + tokenId: crypto.randomBytes(16), + uid: crypto.randomBytes(16) + } + }, + headers: {}, + payload: { + duration: 0, + publicKey: { + algorithm: 'RS', + n: 'bar', + e: 'baz' + } + }, + query: {} + } + var signRoutes = makeRoutes({ + config: { + memcache: { + address: '127.0.0.1:11211', + idle: 100 + } + }, + log: mockLog + }) + + return new P(function (resolve) { + getRoute(signRoutes, '/certificate/sign') + .handler(mockRequest, resolve) + }) + .then( + function () { + t.equal(mockLog.activityEvent.callCount, 1) + t.equal(mockLog.activityEvent.args[0].length, 3) + t.equal(mockLog.activityEvent.args[0][0], 'account.signed') + t.equal(mockLog.activityEvent.args[0][1], mockRequest) + t.deepEqual(mockLog.activityEvent.args[0][2], { + uid: mockRequest.auth.credentials.uid.toString('hex'), + account_created_at: mockRequest.auth.credentials.accountCreatedAt, + device_id: mockRequest.auth.credentials.deviceId.toString('hex') + }) + }, + function () { + t.fail('request should have succeeded') + } + ) + } +) + +function makeRoutes (options) { + options = options || {} + + var log = options.log || mocks.mockLog() + var config = options.config || {} + + return require('../../lib/routes/sign')( + log, + isA, + error, + options.signer || { + sign: function () { + return P.resolve({}) + } + }, + options.db || { + updateSessionToken: function () {}, + updateLocale: function () {} + }, + options.domain || 'wibble', + options.metricsContext || require('../../lib/metrics/context')(log, config) + ) +} + diff --git a/test/mocks.js b/test/mocks.js index e03f18b4..b6300d30 100644 --- a/test/mocks.js +++ b/test/mocks.js @@ -12,18 +12,19 @@ var P = require('../lib/promise') var crypto = require('crypto') var DB_METHOD_NAMES = ['account', 'createAccount', 'createDevice', 'createKeyFetchToken', - 'createSessionToken', 'devices', 'deleteAccount', 'deleteDevice', - 'deletePasswordChangeToken', 'deleteVerificationReminder', 'emailRecord', 'resetAccount', - 'sessionTokenWithVerificationStatus', 'sessions', 'updateDevice', 'verifyTokens', 'verifyEmail'] + 'createSessionToken', 'deleteAccount', 'deleteDevice', 'deleteKeyFetchToken', + 'deletePasswordChangeToken', 'deleteVerificationReminder', 'devices', + 'emailRecord', 'resetAccount', 'sessions', 'sessionTokenWithVerificationStatus', + 'updateDevice', 'verifyEmail', 'verifyTokens'] -var LOG_METHOD_NAMES = ['trace', 'increment', 'info', 'error', 'begin', 'warn', - 'activityEvent', 'event', 'timing'] +var LOG_METHOD_NAMES = ['trace', 'increment', 'info', 'error', 'begin', 'warn', 'timing', + 'activityEvent', 'event'] var MAILER_METHOD_NAMES = ['sendVerifyCode', 'sendVerifyLoginEmail', 'sendNewDeviceLoginNotification', 'sendPasswordChangedNotification', 'sendPostVerifyEmail'] -var METRICS_CONTEXT_METHOD_NAMES = ['add', 'validate'] +var METRICS_CONTEXT_METHOD_NAMES = ['stash', 'gather', 'validate'] var PUSH_METHOD_NAMES = ['notifyDeviceConnected', 'notifyDeviceDisconnected', 'notifyUpdate'] @@ -53,7 +54,9 @@ function mockDB (data, errors) { return P.resolve({ uid: data.uid, email: data.email, - emailVerified: data.emailVerified + emailCode: data.emailCode, + emailVerified: data.emailVerified, + wrapWrapKb: data.wrapWrapKb }) }), createDevice: sinon.spy(function () { @@ -67,7 +70,9 @@ function mockDB (data, errors) { }), createKeyFetchToken: sinon.spy(function () { return P.resolve({ - data: crypto.randomBytes(32) + data: crypto.randomBytes(32), + tokenId: data.keyFetchTokenId, + uid: data.uid }) }), createSessionToken: sinon.spy(function () { @@ -78,6 +83,7 @@ function mockDB (data, errors) { lastAuthAt: function () { return Date.now() }, + tokenId: data.sessionTokenId, tokenVerificationId: data.tokenVerificationId, tokenVerified: ! data.tokenVerificationId, uid: data.uid