refactor(tests): Reorganize local tests (#1629) r=vladikoff,philbooth

This commit is contained in:
Vijay Budhram 2017-01-27 15:07:35 -05:00 коммит произвёл Vlad Filippov
Родитель 2e84e07e02
Коммит 38d4957f28
37 изменённых файлов: 1250 добавлений и 1010 удалений

Просмотреть файл

@ -4,7 +4,7 @@ set -euo pipefail
glob=$*
if [ "$glob" == "" ]; then
glob="test/local test/remote"
glob="test/local/* test/remote/*"
fi
./scripts/gen_keys.js

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const assert = require('insist')
const base32 = require('../../lib/crypto/base32')
const base32 = require('../../../lib/crypto/base32')
describe('base32', () => {
it('takes 1 integer argument, returns a function', () => {

Просмотреть файл

@ -5,7 +5,7 @@
'use strict'
const assert = require('assert')
const butil = require('../../lib/crypto/butil')
const butil = require('../../../lib/crypto/butil')
describe('butil', () => {

Просмотреть файл

@ -5,7 +5,7 @@
'use strict'
const assert = require('insist')
const hkdf = require('../../lib/crypto/hkdf')
const hkdf = require('../../../lib/crypto/hkdf')
describe('hkdf', () => {

Просмотреть файл

@ -5,7 +5,7 @@
'use strict'
const assert = require('insist')
const pbkdf2 = require('../../lib/crypto/pbkdf2')
const pbkdf2 = require('../../../lib/crypto/pbkdf2')
const ITERATIONS = 20000
const LENGTH = 32

Просмотреть файл

@ -5,14 +5,14 @@
'use strict'
const assert = require('insist')
var promise = require('../../lib/promise')
var promise = require('../../../lib/promise')
var config = { scrypt: { maxPending: 5 } }
var log = {
buffer: [],
warn: function(obj){ log.buffer.push(obj) },
}
var scrypt = require('../../lib/crypto/scrypt')(log, config)
var scrypt = require('../../../lib/crypto/scrypt')(log, config)
describe('scrypt', () => {
it(

Просмотреть файл

@ -6,10 +6,10 @@ const assert = require('insist')
var EventEmitter = require('events').EventEmitter
var sinon = require('sinon')
var spyLog = require('../mocks').spyLog
var error = require('../../lib/error')
var P = require('../../lib/promise')
var bounces = require('../../lib/email/bounces')
var spyLog = require('../../mocks').spyLog
var error = require('../../../lib/error')
var P = require('../../../lib/promise')
var bounces = require('../../../lib/email/bounces')
var mockBounceQueue = new EventEmitter()
mockBounceQueue.start = function start() {}

Просмотреть файл

@ -6,8 +6,8 @@ const assert = require('insist')
const EventEmitter = require('events').EventEmitter
const sinon = require('sinon')
const spyLog = require('../mocks').spyLog
const delivery = require('../../lib/email/delivery')
const spyLog = require('../../mocks').spyLog
const delivery = require('../../../lib/email/delivery')
const mockDeliveryQueue = new EventEmitter()
mockDeliveryQueue.start = function start() {

Просмотреть файл

@ -9,11 +9,11 @@ const log = {
flowEvent: () => {},
error() {}
}
const mocks = require('../mocks')
var error = require('../../lib/error.js')
const mocks = require('../../mocks')
var error = require('../../../lib/error.js')
var nock = require('nock')
var Customs = require('../../lib/customs.js')(log, error)
var Customs = require('../../../lib/customs.js')(log, error)
var CUSTOMS_URL_REAL = 'http://localhost:7000'
var CUSTOMS_URL_MISSING = 'http://localhost:7001'

Просмотреть файл

@ -7,9 +7,9 @@
const assert = require('insist')
var uuid = require('uuid')
var crypto = require('crypto')
var mocks = require('../mocks')
var mocks = require('../../mocks')
var modulePath = '../../lib/devices'
var modulePath = '../../../lib/devices'
describe('devices', () => {
it('should be an exported function', () => {

Просмотреть файл

@ -4,7 +4,7 @@
const assert = require('insist')
var messages = require('joi/lib/language')
var AppError = require('../../lib/error')
var AppError = require('../../../lib/error')
describe('AppErrors', () => {

Просмотреть файл

@ -24,7 +24,7 @@ const config = {
securityHistory: {}
}
const features = proxyquire('../../lib/features', {
const features = proxyquire('../../../lib/features', {
crypto: crypto
})(config)

Просмотреть файл

@ -6,7 +6,8 @@
const assert = require('insist')
const proxyquire = require('proxyquire')
const mockLog = require('../mocks').mockLog
const mockLog = require('../../mocks').mockLog
const modulePath = '../../../lib/geodb'
describe('geodb', () => {
it(
@ -25,7 +26,7 @@ describe('geodb', () => {
}
const thisMockLog = mockLog({})
const getGeoData = proxyquire('../../lib/geodb', moduleMocks)(thisMockLog)
const getGeoData = proxyquire(modulePath, moduleMocks)(thisMockLog)
return getGeoData('63.245.221.32') // MTV
.then(function (geoData) {
assert.equal(geoData.location.city, 'Mountain View')
@ -53,7 +54,7 @@ describe('geodb', () => {
}
const thisMockLog = mockLog({})
const getGeoData = proxyquire('../../lib/geodb', moduleMocks)(thisMockLog)
const getGeoData = proxyquire(modulePath, moduleMocks)(thisMockLog)
return getGeoData('8.8.8.8')
.then(function (geoData) {
assert.deepEqual(geoData, {})

Просмотреть файл

@ -28,7 +28,7 @@ mocks.mozlog.config = sinon.spy()
mocks['./metrics/statsd'] = function () {
return statsd
}
var log = proxyquire('../../lib/log', mocks)('foo', 'bar')
var log = proxyquire('../../../lib/log', mocks)('foo', 'bar')
const emitRouteFlowEvent = sinon.spy()

Просмотреть файл

@ -5,14 +5,14 @@
'use strict'
const assert = require('insist')
var config = require('../../config').getProperties()
var config = require('../../../config/index').getProperties()
var log = {}
describe('mailer locales', () => {
let mailer
before(() => {
return require('../../lib/mailer')(config, log)
return require('../../../lib/mailer')(config, log)
.then(m => {
mailer = m
})

Просмотреть файл

@ -11,13 +11,14 @@ var ajv = require('ajv')()
var fs = require('fs')
var path = require('path')
var P = require('../../lib/promise')
var mockLog = require('../mocks').mockLog
var P = require('../../../lib/promise')
var mockLog = require('../../mocks').mockLog
var mockUid = new Buffer('foo')
var mockConfig = {}
var PUSH_PAYLOADS_SCHEMA_PATH = '../../docs/pushpayloads.schema.json'
var PUSH_PAYLOADS_SCHEMA_PATH = '../../../docs/pushpayloads.schema.json'
var TTL = '42'
const pushModulePath = '../../../lib/push'
var mockDbEmpty = {
devices: function () {
@ -58,7 +59,7 @@ describe('push', () => {
it(
'pushToDevices throws on device not found',
() => {
var push = require('../../lib/push')(mockLog(), mockDbEmpty, mockConfig)
var push = require(pushModulePath)(mockLog(), mockDbEmpty, mockConfig)
sinon.spy(push, 'sendPush')
return push.pushToDevices([mockUid], 'bogusid').then(function () {
@ -80,7 +81,7 @@ describe('push', () => {
}
})
var push = require('../../lib/push')(thisMockLog, mockDbEmpty, mockConfig)
var push = require(pushModulePath)(thisMockLog, mockDbEmpty, mockConfig)
return push.pushToAllDevices(mockUid, 'accountVerify')
}
)
@ -96,7 +97,7 @@ describe('push', () => {
}
}
var push = proxyquire('../../lib/push', mocks)(mockLog(), mockDbResult, mockConfig)
var push = proxyquire(pushModulePath, mocks)(mockLog(), mockDbResult, mockConfig)
var options = { excludedDeviceIds: [mockDevices[0].id] }
return push.pushToAllDevices(mockUid, 'accountVerify', options)
}
@ -105,7 +106,7 @@ describe('push', () => {
it(
'pushToAllDevices calls sendPush',
() => {
var push = require('../../lib/push')(mockLog(), mockDbResult, mockConfig)
var push = require(pushModulePath)(mockLog(), mockDbResult, mockConfig)
sinon.stub(push, 'sendPush')
var excluded = [mockDevices[0].id]
var data = new Buffer('foobar')
@ -125,7 +126,7 @@ describe('push', () => {
it(
'pushToDevices calls sendPush',
() => {
var push = require('../../lib/push')(mockLog(), mockDbResult, mockConfig)
var push = require(pushModulePath)(mockLog(), mockDbResult, mockConfig)
sinon.stub(push, 'sendPush')
var data = new Buffer('foobar')
var options = { data: data, TTL: TTL }
@ -144,7 +145,7 @@ describe('push', () => {
it(
'pushToDevice calls pushToDevices',
() => {
var push = require('../../lib/push')(mockLog(), mockDbResult, mockConfig)
var push = require(pushModulePath)(mockLog(), mockDbResult, mockConfig)
sinon.stub(push, 'pushToDevices')
var data = new Buffer('foobar')
var options = { data: data, TTL: TTL }
@ -181,7 +182,7 @@ describe('push', () => {
}
}
var push = proxyquire('../../lib/push', mocks)(thisMockLog, mockDbResult, mockConfig)
var push = proxyquire(pushModulePath, mocks)(thisMockLog, mockDbResult, mockConfig)
return push.sendPush(mockUid, mockDevices, 'accountVerify')
.then(() => {
assert.equal(successCalled, 2)
@ -211,7 +212,7 @@ describe('push', () => {
}
}
var push = proxyquire('../../lib/push', mocks)(thisMockLog, mockDbResult, mockConfig)
var push = proxyquire(pushModulePath, mocks)(thisMockLog, mockDbResult, mockConfig)
var options = { TTL: TTL }
return push.sendPush(mockUid, mockDevices, 'accountVerify', options)
.then(() => {
@ -237,7 +238,7 @@ describe('push', () => {
}
}
var push = proxyquire('../../lib/push', mocks)(mockLog(), mockDbResult, mockConfig)
var push = proxyquire(pushModulePath, mocks)(mockLog(), mockDbResult, mockConfig)
var options = { data: data }
return push.sendPush(mockUid, mockDevices, 'accountVerify', options)
.then(() => {
@ -266,7 +267,7 @@ describe('push', () => {
'pushAuthKey': 'bogus'
}]
var push = require('../../lib/push')(thisMockLog, mockDbResult, mockConfig)
var push = require(pushModulePath)(thisMockLog, mockDbResult, mockConfig)
var options = { data: new Buffer('foobar') }
return push.sendPush(mockUid, devices, 'accountVerify', options)
.then(() => {
@ -293,7 +294,7 @@ describe('push', () => {
'name': 'My Phone'
}]
var push = require('../../lib/push')(thisMockLog, mockDbResult, mockConfig)
var push = require(pushModulePath)(thisMockLog, mockDbResult, mockConfig)
return push.sendPush(mockUid, devices, 'accountVerify')
.then(() => {
assert.equal(count, 1)
@ -322,7 +323,7 @@ describe('push', () => {
}
}
var push = proxyquire('../../lib/push', mocks)(thisMockLog, mockDbResult, mockConfig)
var push = proxyquire(pushModulePath, mocks)(thisMockLog, mockDbResult, mockConfig)
return push.sendPush(mockUid, [mockDevices[0]], 'accountVerify')
.then(() => {
assert.equal(count, 1)
@ -350,7 +351,7 @@ describe('push', () => {
}
}
}
var push = proxyquire('../../lib/push', mocks)(thisMockLog, mockDbResult, mockConfig)
var push = proxyquire(pushModulePath, mocks)(thisMockLog, mockDbResult, mockConfig)
return push.sendPush(mockUid, devices, 'accountVerify').then(function () {
assert.equal(thisMockLog.error.callCount, 0, 'log.error was not called')
@ -398,7 +399,7 @@ describe('push', () => {
}
}
var push = proxyquire('../../lib/push', mocks)(thisMockLog, mockDb, mockConfig)
var push = proxyquire(pushModulePath, mocks)(thisMockLog, mockDb, mockConfig)
return push.sendPush(mockUid, [mockDevices[0]], 'accountVerify')
.then(() => {
assert.equal(count, 1)
@ -409,7 +410,7 @@ describe('push', () => {
it(
'notifyUpdate calls pushToAllDevices',
() => {
var push = require('../../lib/push')(mockLog(), mockDbEmpty, mockConfig)
var push = require(pushModulePath)(mockLog(), mockDbEmpty, mockConfig)
sinon.spy(push, 'pushToAllDevices')
return push.notifyUpdate(mockUid, 'passwordReset')
.then(function() {
@ -424,7 +425,7 @@ describe('push', () => {
it(
'notifyUpdate without a 2nd arg calls pushToAllDevices with a accountVerify reason',
() => {
var push = require('../../lib/push')(mockLog(), mockDbEmpty, mockConfig)
var push = require(pushModulePath)(mockLog(), mockDbEmpty, mockConfig)
sinon.spy(push, 'pushToAllDevices')
return push.notifyUpdate(mockUid)
.then(function() {
@ -439,7 +440,7 @@ describe('push', () => {
it(
'notifyDeviceConnected calls pushToAllDevices',
() => {
var push = require('../../lib/push')(mockLog(), mockDbEmpty, mockConfig)
var push = require(pushModulePath)(mockLog(), mockDbEmpty, mockConfig)
sinon.spy(push, 'pushToAllDevices')
var deviceId = 'gjfkd5434jk5h5fd'
var deviceName = 'My phone'
@ -473,7 +474,7 @@ describe('push', () => {
it(
'notifyDeviceDisconnected calls pushToDevice',
() => {
var push = require('../../lib/push')(mockLog(), mockDbResult, mockConfig)
var push = require(pushModulePath)(mockLog(), mockDbResult, mockConfig)
sinon.spy(push, 'pushToDevice')
var idToDisconnect = mockDevices[0].id
var expectedData = {
@ -514,7 +515,7 @@ describe('push', () => {
}
}
}
var push = proxyquire('../../lib/push', mocks)(mockLog(), mockDbResult, mockConfig)
var push = proxyquire(pushModulePath, mocks)(mockLog(), mockDbResult, mockConfig)
sinon.spy(push, 'sendPush')
var expectedData = {
version: 1,
@ -550,7 +551,7 @@ describe('push', () => {
}
}
}
var push = proxyquire('../../lib/push', mocks)(mockLog(), mockDbEmpty, mockConfig)
var push = proxyquire(pushModulePath, mocks)(mockLog(), mockDbEmpty, mockConfig)
sinon.spy(push, 'sendPush')
var expectedData = {
version: 1,
@ -590,7 +591,7 @@ describe('push', () => {
var mockConfig = {
publicUrl: 'https://example.com',
vapidKeysFile: path.join(__dirname, '..', 'config', 'mock-vapid-keys.json')
vapidKeysFile: path.join(__dirname, '../../', 'config', 'mock-vapid-keys.json')
}
var mocks = {
@ -605,7 +606,7 @@ describe('push', () => {
}
}
var push = proxyquire('../../lib/push', mocks)(thisMockLog, mockDbResult, mockConfig)
var push = proxyquire(pushModulePath, mocks)(thisMockLog, mockDbResult, mockConfig)
return push.sendPush(mockUid, mockDevices, 'accountVerify')
.then(() => {
assert.equal(count, 1)
@ -627,7 +628,7 @@ describe('push', () => {
}
}
var push = proxyquire('../../lib/push', mocks)(thisMockLog, mockDbResult, mockConfig)
var push = proxyquire(pushModulePath, mocks)(thisMockLog, mockDbResult, mockConfig)
return push.sendPush(mockUid, mockDevices, 'anUnknownReasonString').then(
function () {
assert(false, 'calling sendPush should have failed')

Просмотреть файл

@ -5,7 +5,7 @@
'use strict'
const assert = require('insist')
const server = require('../../lib/server')
const server = require('../../../lib/server')
describe('lib/server', () => {
describe('trimLocale', () => {

Просмотреть файл

@ -8,11 +8,13 @@ const assert = require('insist')
var proxyquire = require('proxyquire')
var uuid = require('uuid')
var P = require('../../lib/promise')
var mockLog = require('../mocks').mockLog
var P = require('../../../lib/promise')
var mockLog = require('../../mocks').mockLog
var zeroBuffer16 = Buffer('00000000000000000000000000000000', 'hex')
const verificationModulePath = '../../../lib/verification-reminders'
var ACCOUNT = {
uid: uuid.v4('binary'),
email: 'reminder' + Math.random() + '@bar.com',
@ -55,7 +57,7 @@ describe('verification reminders', () => {
}
})
var verificationReminder = proxyquire('../../lib/verification-reminders', moduleMocks)(thisMockLog, mockDb)
var verificationReminder = proxyquire(verificationModulePath, moduleMocks)(thisMockLog, mockDb)
return P.all([
verificationReminder.create(reminderData),
@ -84,7 +86,7 @@ describe('verification reminders', () => {
}
}
var verificationReminder = proxyquire('../../lib/verification-reminders', moduleMocks)(mockLog, mockDb)
var verificationReminder = proxyquire(verificationModulePath, moduleMocks)(mockLog, mockDb)
verificationReminder.create(reminderData)
.then(function (result) {
assert.equal(result, false)
@ -111,7 +113,7 @@ describe('verification reminders', () => {
}
}
var verificationReminder = proxyquire('../../lib/verification-reminders', {})(thisMockLog, thisMockDb)
var verificationReminder = proxyquire(verificationModulePath, {})(thisMockLog, thisMockDb)
return verificationReminder.delete(reminderData).then(() => {
assert.equal(count, 1)
})
@ -135,7 +137,7 @@ describe('verification reminders', () => {
}
}
var verificationReminder = proxyquire('../../lib/verification-reminders', {})(thisMockLog, thisMockDb)
var verificationReminder = proxyquire(verificationModulePath, {})(thisMockLog, thisMockDb)
return verificationReminder.delete(reminderData).then(() => {
assert.equal(count, 1)
})

Просмотреть файл

@ -7,10 +7,10 @@
const assert = require('insist')
const crypto = require('crypto')
const sinon = require('sinon')
const mocks = require('../mocks')
const mocks = require('../../mocks')
const log = mocks.spyLog()
const Memcached = require('memcached')
const metricsContextModule = require('../../lib/metrics/context')
const metricsContextModule = require('../../../lib/metrics/context')
const metricsContext = metricsContextModule(log, {
memcached: {
address: '127.0.0.1:1121',
@ -18,7 +18,7 @@ const metricsContext = metricsContextModule(log, {
lifetime: 30
}
})
const P = require('../../lib/promise')
const P = require('../../../lib/promise')
describe('metricsConext', () => {
@ -455,7 +455,7 @@ describe('metricsConext', () => {
it(
'metricsContext.stash with config.memcached.address === "none"',
() => {
var metricsContextWithoutMemcached = require('../../lib/metrics/context')(log, {
var metricsContextWithoutMemcached = require('../../../lib/metrics/context')(log, {
memcached: {
address: 'none',
idle: 500,
@ -487,7 +487,7 @@ describe('metricsConext', () => {
it(
'metricsContext.gather with config.memcached.address === "none"',
() => {
var metricsContextWithoutMemcached = require('../../lib/metrics/context')(log, {
var metricsContextWithoutMemcached = require('../../../lib/metrics/context')(log, {
memcached: {
address: 'none',
idle: 500,
@ -611,7 +611,7 @@ describe('metricsConext', () => {
it(
'metricsContext.clear with config.memcached.address === "none"',
() => {
const metricsContextWithoutMemcached = require('../../lib/metrics/context')(log, {
const metricsContextWithoutMemcached = require('../../../lib/metrics/context')(log, {
memcached: {
address: 'none',
idle: 500,
@ -666,7 +666,7 @@ describe('metricsConext', () => {
}
}
const metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
const metricsContext = require('../../../lib/metrics/context')(mockLog, mockConfig)
const result = metricsContext.validate.call(mockRequest)
assert.strictEqual(result, true, 'result was true')
@ -704,7 +704,7 @@ describe('metricsConext', () => {
}
}
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
var metricsContext = require('../../../lib/metrics/context')(mockLog, mockConfig)
var valid = metricsContext.validate.call(mockRequest)
assert(!valid, 'the data is treated as invalid')
@ -740,7 +740,7 @@ describe('metricsConext', () => {
}
}
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
var metricsContext = require('../../../lib/metrics/context')(mockLog, mockConfig)
var valid = metricsContext.validate.call(mockRequest)
assert(!valid, 'the data is treated as invalid')
@ -777,7 +777,7 @@ describe('metricsConext', () => {
}
}
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
var metricsContext = require('../../../lib/metrics/context')(mockLog, mockConfig)
var valid = metricsContext.validate.call(mockRequest)
assert(!valid, 'the data is treated as invalid')
@ -815,7 +815,7 @@ describe('metricsConext', () => {
}
}
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
var metricsContext = require('../../../lib/metrics/context')(mockLog, mockConfig)
var valid = metricsContext.validate.call(mockRequest)
assert(!valid, 'the data is treated as invalid')
@ -853,7 +853,7 @@ describe('metricsConext', () => {
}
}
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
var metricsContext = require('../../../lib/metrics/context')(mockLog, mockConfig)
var valid = metricsContext.validate.call(mockRequest)
assert(!valid, 'the data is treated as invalid')
@ -898,7 +898,7 @@ describe('metricsConext', () => {
})
try {
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
var metricsContext = require('../../../lib/metrics/context')(mockLog, mockConfig)
var valid = metricsContext.validate.call(mockRequest)
} finally {
Date.now.restore()
@ -946,7 +946,7 @@ describe('metricsConext', () => {
})
try {
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
var metricsContext = require('../../../lib/metrics/context')(mockLog, mockConfig)
var valid = metricsContext.validate.call(mockRequest)
} finally {
Date.now.restore()
@ -994,7 +994,7 @@ describe('metricsConext', () => {
})
try {
var metricsContext = require('../../lib/metrics/context')(mockLog, mockConfig)
var metricsContext = require('../../../lib/metrics/context')(mockLog, mockConfig)
var valid = metricsContext.validate.call(mockRequest)
} finally {
Date.now.restore()

Просмотреть файл

@ -11,8 +11,8 @@ const log = {
error: sinon.spy(),
flowEvent: sinon.spy()
}
const events = require('../../lib/metrics/events')(log)
const mocks = require('../mocks')
const events = require('../../../lib/metrics/events')(log)
const mocks = require('../../mocks')
describe('metrics/events', () => {
it('interface is correct', () => {

Просмотреть файл

@ -5,8 +5,8 @@
'use strict'
const assert = require('insist')
var StatsDCollector = require('../../lib/metrics/statsd')
var mockLog = require('../mocks').mockLog()
var StatsDCollector = require('../../../lib/metrics/statsd')
var mockLog = require('../../mocks').mockLog()
describe('metrics/statsd', () => {
it(
@ -118,7 +118,7 @@ describe('metrics/statsd', () => {
var statsd = new StatsDCollector(mockLog)
statsd.init()
statsd.client = new StatsDMock()
var log = require('../../lib/log')('info')
var log = require('../../../lib/log')('info')
log.statsd = statsd
log.increment('some-event')
assert.equal(count, 1)
@ -182,7 +182,7 @@ describe('metrics/statsd', () => {
var statsd = new StatsDCollector(mockLog)
statsd.init()
statsd.client = new StatsDMock()
var log = require('../../lib/log')('info')
var log = require('../../../lib/log')('info')
log.statsd = statsd
log.timing('foo', 1)
assert.equal(count, 1)

Просмотреть файл

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -7,19 +7,18 @@
var sinon = require('sinon')
const assert = require('insist')
var mocks = require('../mocks')
var getRoute = require('../routes_helpers').getRoute
var mocks = require('../../mocks')
var getRoute = require('../../routes_helpers').getRoute
var proxyquire = require('proxyquire')
var P = require('../../lib/promise')
var P = require('../../../lib/promise')
var uuid = require('uuid')
var crypto = require('crypto')
var isA = require('joi')
var error = require('../../lib/error')
var log = require('../../lib/log')
var error = require('../../../lib/error')
var log = require('../../../lib/log')
var TEST_EMAIL = 'foo@gmail.com'
var TEST_EMAIL_INVALID = 'example@dotless-domain'
var makeRoutes = function (options, requireMocks) {
options = options || {}
@ -41,17 +40,17 @@ var makeRoutes = function (options, requireMocks) {
config.signinUnblock = config.signinUnblock || {}
var log = options.log || mocks.mockLog()
var Password = options.Password || require('../../lib/crypto/password')(log, config)
var Password = options.Password || require('../../../lib/crypto/password')(log, config)
var db = options.db || mocks.mockDB()
var isPreVerified = require('../../lib/preverifier')(error, config)
var isPreVerified = require('../../../lib/preverifier')(error, config)
var customs = options.customs || {
check: function () { return P.resolve(true) }
}
var checkPassword = options.checkPassword || require('../../lib/routes/utils/password_check')(log, config, Password, customs, db)
var push = options.push || require('../../lib/push')(log, db, {})
return proxyquire('../../lib/routes/account', requireMocks || {})(
var checkPassword = options.checkPassword || require('../../../lib/routes/utils/password_check')(log, config, Password, customs, db)
var push = options.push || require('../../../lib/push')(log, db, {})
return proxyquire('../../../lib/routes/account', requireMocks || {})(
log,
require('../../lib/crypto/random'),
require('../../../lib/crypto/random'),
P,
uuid,
isA,
@ -64,7 +63,7 @@ var makeRoutes = function (options, requireMocks) {
isPreVerified,
checkPassword,
push,
options.devices || require('../../lib/devices')(log, db, push)
options.devices || require('../../../lib/devices')(log, db, push)
)
}
@ -82,236 +81,6 @@ function runTest (route, request, assertions) {
.then(assertions)
}
describe('/recovery_email/status', function () {
var config = {}
var mockDB = mocks.mockDB()
var pushCalled
var mockLog = mocks.mockLog({
increment: function (name) {
if (name === 'recovery_email_reason.push') {
pushCalled = true
}
}
})
var accountRoutes = makeRoutes({
config: config,
db: mockDB,
log: mockLog
})
var route = getRoute(accountRoutes, '/recovery_email/status')
var mockRequest = mocks.mockRequest({
credentials: {
uid: uuid.v4('binary').toString('hex'),
email: TEST_EMAIL
}
})
describe('invalid email', function () {
var mockRequest = mocks.mockRequest({
credentials: {
email: TEST_EMAIL_INVALID
}
})
it('unverified account', function () {
mockRequest.auth.credentials.emailVerified = false
return runTest(route, mockRequest).then(() => assert.ok(false), function (response) {
assert.equal(mockDB.deleteAccount.callCount, 1)
assert.equal(mockDB.deleteAccount.firstCall.args[0].email, TEST_EMAIL_INVALID)
assert.equal(response.errno, error.ERRNO.INVALID_TOKEN)
})
.then(function () {
mockDB.deleteAccount.reset()
})
})
it('verified account', function () {
mockRequest.auth.credentials.uid = uuid.v4('binary').toString('hex')
mockRequest.auth.credentials.emailVerified = true
mockRequest.auth.credentials.tokenVerified = true
return runTest(route, mockRequest, function (response) {
assert.equal(mockDB.deleteAccount.callCount, 0)
assert.deepEqual(response, {
email: TEST_EMAIL_INVALID,
verified: true,
emailVerified: true,
sessionVerified: true
})
})
})
})
it('valid email, verified account', function () {
pushCalled = false
var mockRequest = mocks.mockRequest({
credentials: {
uid: uuid.v4('binary').toString('hex'),
email: TEST_EMAIL,
emailVerified: true,
tokenVerified: true
},
query: {
reason: 'push'
}
})
return runTest(route, mockRequest, function (response) {
assert.equal(pushCalled, true)
assert.deepEqual(response, {
email: TEST_EMAIL,
verified: true,
emailVerified: true,
sessionVerified: true
})
})
})
it('verified account, verified session', function () {
mockRequest.auth.credentials.emailVerified = true
mockRequest.auth.credentials.tokenVerified = true
return runTest(route, mockRequest, function (response) {
assert.deepEqual(response, {
email: TEST_EMAIL,
verified: true,
sessionVerified: true,
emailVerified: true
})
})
})
it('verified account, unverified session, must verify session', function () {
mockRequest.auth.credentials.emailVerified = true
mockRequest.auth.credentials.tokenVerified = false
mockRequest.auth.credentials.mustVerify = true
return runTest(route, mockRequest, function (response) {
assert.deepEqual(response, {
email: TEST_EMAIL,
verified: false,
sessionVerified: false,
emailVerified: true
})
})
})
it('verified account, unverified session, neednt verify session', function () {
mockRequest.auth.credentials.emailVerified = true
mockRequest.auth.credentials.tokenVerified = false
mockRequest.auth.credentials.mustVerify = false
return runTest(route, mockRequest, function (response) {
assert.deepEqual(response, {
email: TEST_EMAIL,
verified: true,
sessionVerified: false,
emailVerified: true
})
})
})
})
describe('/recovery_email/resend_code', () => {
const config = {}
const mockDB = mocks.mockDB()
const mockLog = mocks.mockLog()
mockLog.flowEvent = sinon.spy(() => {
return P.resolve()
})
const mockMailer = mocks.mockMailer()
const mockMetricsContext = mocks.mockMetricsContext()
const accountRoutes = makeRoutes({
config: config,
db: mockDB,
log: mockLog,
mailer: mockMailer
})
const route = getRoute(accountRoutes, '/recovery_email/resend_code')
it('verification', () => {
const mockRequest = mocks.mockRequest({
log: mockLog,
metricsContext: mockMetricsContext,
credentials: {
uid: uuid.v4('binary').toString('hex'),
email: TEST_EMAIL,
emailVerified: false,
tokenVerified: false,
uaBrowser: 'Firefox',
uaBrowserVersion: 52,
uaOS: 'Mac OS X',
uaOSVersion: '10.10'
},
query: {},
payload: {
metricsContext: {
flowBeginTime: Date.now(),
flowId: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103'
}
}
})
mockLog.flowEvent.reset()
return runTest(route, mockRequest, response => {
assert.equal(mockLog.flowEvent.callCount, 1, 'log.flowEvent called once')
assert.equal(mockLog.flowEvent.args[0][0].event, 'email.verification.resent')
assert.equal(mockMailer.sendVerifyCode.callCount, 1)
const args = mockMailer.sendVerifyCode.args[0]
assert.equal(args[2].uaBrowser, 'Firefox')
assert.equal(args[2].uaBrowserVersion, '52')
assert.equal(args[2].uaOS, 'Mac OS X')
assert.equal(args[2].uaOSVersion, '10.10')
assert.strictEqual(args[2].uaDeviceType, undefined)
})
})
it('confirmation', () => {
const mockRequest = mocks.mockRequest({
log: mockLog,
metricsContext: mockMetricsContext,
credentials: {
uid: uuid.v4('binary').toString('hex'),
email: TEST_EMAIL,
emailVerified: true,
tokenVerified: false,
uaBrowser: 'Firefox',
uaBrowserVersion: '50',
uaOS: 'Android',
uaOSVersion: '6',
uaDeviceType: 'tablet'
},
query: {},
payload: {
metricsContext: {
flowBeginTime: Date.now(),
flowId: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103'
}
}
})
mockLog.flowEvent.reset()
return runTest(route, mockRequest, response => {
assert.equal(mockLog.flowEvent.callCount, 1, 'log.flowEvent called once')
assert.equal(mockLog.flowEvent.args[0][0].event, 'email.confirmation.resent')
assert.equal(mockMailer.sendVerifyLoginEmail.callCount, 1)
const args = mockMailer.sendVerifyLoginEmail.args[0]
assert.equal(args[2].uaBrowser, 'Firefox')
assert.equal(args[2].uaBrowserVersion, '50')
assert.equal(args[2].uaOS, 'Android')
assert.equal(args[2].uaOSVersion, '6')
assert.strictEqual(args[2].uaDeviceType, 'tablet')
})
})
})
describe('/account/reset', function () {
it('should do things', () => {
var uid = uuid.v4('binary')
@ -410,320 +179,6 @@ describe('/account/reset', function () {
})
})
describe('/account/device', function () {
var config = {}
var uid = uuid.v4('binary')
var deviceId = crypto.randomBytes(16)
var mockRequest = mocks.mockRequest({
credentials: {
deviceCallbackPublicKey: '',
deviceCallbackURL: '',
deviceId: deviceId,
deviceName: 'my awesome device',
deviceType: 'desktop',
tokenId: crypto.randomBytes(16),
uid: uid
},
payload: {
id: deviceId.toString('hex'),
name: 'my awesome device'
}
})
var mockDevices = mocks.mockDevices()
var mockLog = mocks.spyLog()
var accountRoutes = makeRoutes({
config: config,
devices: mockDevices,
log: mockLog
})
var route = getRoute(accountRoutes, '/account/device')
it('identical data', function () {
return runTest(route, mockRequest, function (response) {
assert.equal(mockLog.increment.callCount, 1, 'a counter was incremented')
assert.equal(mockLog.increment.firstCall.args[0], 'device.update.spurious')
assert.deepEqual(response, mockRequest.payload)
})
.then(function () {
mockLog.increment.reset()
})
})
it('different data', function () {
mockRequest.auth.credentials.deviceId = crypto.randomBytes(16)
var payload = mockRequest.payload
payload.name = 'my even awesomer device'
payload.type = 'phone'
payload.pushCallback = 'https://push.services.mozilla.com/123456'
payload.pushPublicKey = 'SomeEncodedBinaryStuffThatDoesntGetValidedByThisTest'
return runTest(route, mockRequest, function (response) {
assert.equal(mockLog.increment.callCount, 5, 'the counters were incremented')
assert.equal(mockLog.increment.getCall(0).args[0], 'device.update.sessionToken')
assert.equal(mockLog.increment.getCall(1).args[0], 'device.update.name')
assert.equal(mockLog.increment.getCall(2).args[0], 'device.update.type')
assert.equal(mockLog.increment.getCall(3).args[0], 'device.update.pushCallback')
assert.equal(mockLog.increment.getCall(4).args[0], 'device.update.pushPublicKey')
assert.equal(mockDevices.upsert.callCount, 1, 'devices.upsert was called once')
var args = mockDevices.upsert.args[0]
assert.equal(args.length, 3, 'devices.upsert was passed three arguments')
assert.equal(args[0], mockRequest, 'first argument was request object')
assert.deepEqual(args[1].tokenId, mockRequest.auth.credentials.tokenId, 'second argument was session token')
assert.deepEqual(args[1].uid, uid, 'sessionToken.uid was correct')
assert.deepEqual(args[2], mockRequest.payload, 'third argument was payload')
})
.then(function () {
mockLog.increment.reset()
mockDevices.upsert.reset()
})
})
it('with no id in payload', function () {
mockRequest.payload.id = undefined
return runTest(route, mockRequest, function (response) {
assert.equal(mockLog.increment.callCount, 0, 'log.increment was not called')
assert.equal(mockDevices.upsert.callCount, 1, 'devices.upsert was called once')
var args = mockDevices.upsert.args[0]
assert.equal(args[2].id, mockRequest.auth.credentials.deviceId.toString('hex'), 'payload.id defaulted to credentials.deviceId')
})
.then(function () {
mockLog.increment.reset()
mockDevices.upsert.reset()
})
})
it('device updates disabled', function () {
config.deviceUpdatesEnabled = false
return runTest(route, mockRequest, function () {
assert(false, 'should have thrown')
})
.then(() => assert.ok(false), function (err) {
assert.equal(err.output.statusCode, 503, 'correct status code is returned')
assert.equal(err.errno, error.ERRNO.FEATURE_NOT_ENABLED, 'correct errno is returned')
})
})
})
describe('/account/devices/notify', function () {
var config = {}
var uid = uuid.v4('binary')
var mockRequest = mocks.mockRequest({
credentials: {
uid: uid.toString('hex')
}
})
var pushPayload = {
isValid: true,
version: 1,
command: 'sync:collection_changed',
data: {
collections: ['clients']
}
}
var mockPush = mocks.mockPush()
var validate = sinon.spy(function (payload) { return payload.isValid })
var mockAjv = function () {
return {
compile: function () {
return validate
}
}
}
var sandbox = sinon.sandbox.create()
var mockCustoms = mocks.mockCustoms()
var accountRoutes = makeRoutes({
config: config,
customs: mockCustoms,
push: mockPush
}, {
ajv: mockAjv
})
var route = getRoute(accountRoutes, '/account/devices/notify')
it('bad payload', function () {
mockRequest.payload = {
to: ['bogusid1'],
payload: {
isValid: false
}
}
return runTest(route, mockRequest, function () {
assert(false, 'should have thrown')
})
.then(() => assert(false), function (err) {
assert.equal(validate.callCount, 1, 'ajv validator function was called')
assert.equal(mockPush.pushToDevices.callCount, 0, 'mockPush.pushToDevices was not called')
assert.equal(err.errno, 107, 'Correct errno for invalid push payload')
})
})
it('all devices', function () {
mockRequest.payload = {
to: 'all',
excluded: ['bogusid'],
TTL: 60,
payload: pushPayload
}
return runTest(route, mockRequest, function (response) {
assert.equal(mockCustoms.checkAuthenticated.callCount, 1, 'mockCustoms.checkAuthenticated was called once')
assert.equal(mockPush.pushToAllDevices.callCount, 1, 'mockPush.pushToAllDevices was called once')
var args = mockPush.pushToAllDevices.args[0]
assert.equal(args.length, 3, 'mockPush.pushToAllDevices was passed three arguments')
assert.equal(args[0], uid.toString('hex'), 'first argument was the device uid')
assert.equal(args[1], 'devicesNotify', 'second argument was the devicesNotify reason')
assert.deepEqual(args[2], {
data: new Buffer(JSON.stringify(pushPayload)),
excludedDeviceIds: ['bogusid'],
TTL: 60
}, 'third argument was the push options')
})
})
it('specific devices', function () {
mockCustoms.checkAuthenticated.reset()
mockRequest.payload = {
to: ['bogusid1', 'bogusid2'],
TTL: 60,
payload: pushPayload
}
return runTest(route, mockRequest, function (response) {
assert.equal(mockCustoms.checkAuthenticated.callCount, 1, 'mockCustoms.checkAuthenticated was called once')
assert.equal(mockPush.pushToDevices.callCount, 1, 'mockPush.pushToDevices was called once')
var args = mockPush.pushToDevices.args[0]
assert.equal(args.length, 4, 'mockPush.pushToDevices was passed four arguments')
assert.equal(args[0], uid.toString('hex'), 'first argument was the device uid')
assert.deepEqual(args[1], ['bogusid1', 'bogusid2'], 'second argument was the list of device ids')
assert.equal(args[2], 'devicesNotify', 'third argument was the devicesNotify reason')
assert.deepEqual(args[3], {
data: new Buffer(JSON.stringify(pushPayload)),
TTL: 60
}, 'fourth argument was the push options')
})
})
it('device driven notifications disabled', function () {
config.deviceNotificationsEnabled = false
mockRequest.payload = {
to: 'all',
excluded: ['bogusid'],
TTL: 60,
payload: pushPayload
}
return runTest(route, mockRequest, function () {
assert(false, 'should have thrown')
})
.then(() => assert.ok(false), function (err) {
assert.equal(err.output.statusCode, 503, 'correct status code is returned')
assert.equal(err.errno, error.ERRNO.FEATURE_NOT_ENABLED, 'correct errno is returned')
})
})
it('throws error if customs blocked the request', function () {
config.deviceNotificationsEnabled = true
mockCustoms = mocks.mockCustoms({
checkAuthenticated: sandbox.spy(function () {
throw error.tooManyRequests(1)
})
})
route = getRoute(makeRoutes({customs: mockCustoms}), '/account/devices/notify')
return runTest(route, mockRequest, function (response) {
assert(false, 'should have thrown')
})
.then(() => assert(false), function (err) {
assert.equal(mockCustoms.checkAuthenticated.callCount, 1, 'mockCustoms.checkAuthenticated was called once')
assert.equal(err.message, 'Client has sent too many requests')
})
})
it('logs error if no devices found', () => {
mockRequest.payload = {
to: ['bogusid1', 'bogusid2'],
TTL: 60,
payload: pushPayload
}
var mockLog = mocks.spyLog()
var mockPush = mocks.mockPush({
pushToDevices: () => P.reject('Devices ids not found in devices')
})
var mockCustoms = {
checkAuthenticated: () => P.resolve()
}
route = getRoute(makeRoutes({
customs: mockCustoms,
log: mockLog,
push: mockPush
}), '/account/devices/notify')
return runTest(route, mockRequest, function (response) {
assert.equal(JSON.stringify(response), '{}', 'response should not throw push errors')
})
})
})
describe('/account/device/destroy', function () {
it('should work', () => {
var uid = uuid.v4('binary')
var deviceId = crypto.randomBytes(16).toString('hex')
var mockLog = mocks.spyLog()
var mockDB = mocks.mockDB()
var mockRequest = mocks.mockRequest({
credentials: {
uid: uid.toString('hex'),
},
log: mockLog,
payload: {
id: deviceId
}
})
var mockPush = mocks.mockPush()
var accountRoutes = makeRoutes({
db: mockDB,
log: mockLog,
push: mockPush
})
var route = getRoute(accountRoutes, '/account/device/destroy')
return runTest(route, mockRequest, function () {
assert.equal(mockDB.deleteDevice.callCount, 1)
assert.equal(mockPush.notifyDeviceDisconnected.callCount, 1)
assert.equal(mockPush.notifyDeviceDisconnected.firstCall.args[0], mockRequest.auth.credentials.uid)
assert.equal(mockPush.notifyDeviceDisconnected.firstCall.args[1], deviceId)
assert.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
var args = mockLog.activityEvent.args[0]
assert.equal(args.length, 1, 'log.activityEvent was passed one argument')
assert.deepEqual(args[0], {
event: 'device.deleted',
service: undefined,
userAgent: 'test user-agent',
uid: uid.toString('hex'),
device_id: deviceId
}, 'event data was correct')
assert.equal(mockLog.notifyAttachedServices.callCount, 1)
args = mockLog.notifyAttachedServices.args[0]
assert.equal(args.length, 3)
assert.equal(args[0], 'device:delete')
assert.equal(args[1], mockRequest)
var details = args[2]
assert.equal(details.uid, uid.toString('hex'))
assert.equal(details.id, deviceId)
assert.ok(Date.now() - details.timestamp < 100)
})
})
})
describe('/account/create', function () {
it('should create an account', () => {
// We want to test what's actually written to stdout by the logger.
@ -1613,178 +1068,6 @@ describe('/account/login', function () {
})
})
describe('/recovery_email/verify_code', function () {
var uid = uuid.v4('binary').toString('hex')
const mockLog = mocks.spyLog()
const mockRequest = mocks.mockRequest({
log: mockLog,
metricsContext: mocks.mockMetricsContext({
gather (data) {
return Promise.resolve(Object.assign(data, {
flowCompleteSignal: 'account.signed',
flow_time: 10000,
flow_id: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103',
time: Date.now() - 10000
}))
}
}),
query: {},
payload: {
uid: uid,
code: 'e3c5b0e3f5391e134596c27519979b93',
service: 'sync'
}
})
var dbData = {
email: TEST_EMAIL,
emailCode: Buffer(mockRequest.payload.code, 'hex'),
emailVerified: false,
uid: uid
}
var dbErrors = {
verifyTokens: error.invalidVerificationCode({})
}
var mockDB = mocks.mockDB(dbData, dbErrors)
var mockMailer = mocks.mockMailer()
const mockPush = mocks.mockPush()
var mockCustoms = mocks.mockCustoms()
var accountRoutes = makeRoutes({
checkPassword: function () {
return P.resolve(true)
},
config: {},
customs: mockCustoms,
db: mockDB,
log: mockLog,
mailer: mockMailer,
push: mockPush
})
var route = getRoute(accountRoutes, '/recovery_email/verify_code')
describe('verifyTokens rejects with INVALID_VERIFICATION_CODE', function () {
it('without a reminder payload', function () {
return runTest(route, mockRequest, function (response) {
assert.equal(mockDB.verifyTokens.callCount, 1, 'calls verifyTokens')
assert.equal(mockDB.verifyEmail.callCount, 1, 'calls verifyEmail')
assert.equal(mockCustoms.check.callCount, 1, 'calls customs.check')
assert.equal(mockLog.notifyAttachedServices.callCount, 1, 'logs verified')
assert.equal(mockMailer.sendPostVerifyEmail.callCount, 1, 'sendPostVerifyEmail was called once')
assert.equal(mockLog.activityEvent.callCount, 1, 'activityEvent was called once')
let args = mockLog.activityEvent.args[0]
assert.equal(args.length, 1, 'log.activityEvent was passed one argument')
assert.deepEqual(args[0], {
event: 'account.verified',
service: 'sync',
userAgent: 'test user-agent',
uid: uid.toString('hex')
}, 'event data was correct')
assert.equal(mockLog.flowEvent.callCount, 2, 'flowEvent was called twice')
assert.equal(mockLog.flowEvent.args[0][0].event, 'email.verify_code.clicked', 'first event was email.verify_code.clicked')
assert.equal(mockLog.flowEvent.args[1][0].event, 'account.verified', 'second event was event account.verified')
assert.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
args = mockPush.notifyUpdate.args[0]
assert.equal(args.length, 2, 'mockPush.notifyUpdate should have been passed two arguments')
assert.equal(args[0].toString('hex'), uid, 'first argument should have been uid')
assert.equal(args[1], 'accountVerify', 'second argument should have been reason')
assert.equal(JSON.stringify(response), '{}')
})
.then(function () {
mockDB.verifyTokens.reset()
mockDB.verifyEmail.reset()
mockLog.activityEvent.reset()
mockLog.flowEvent.reset()
mockLog.notifyAttachedServices.reset()
mockMailer.sendPostVerifyEmail.reset()
mockPush.notifyUpdate.reset()
})
})
it('with a reminder payload', function () {
mockRequest.payload.reminder = 'second'
return runTest(route, mockRequest, function (response) {
assert.equal(mockLog.activityEvent.callCount, 1, 'activityEvent was called once')
assert.equal(mockLog.flowEvent.callCount, 3, 'flowEvent was called thrice')
assert.equal(mockLog.flowEvent.args[0][0].event, 'email.verify_code.clicked', 'first event was email.verify_code.clicked')
assert.equal(mockLog.flowEvent.args[1][0].event, 'account.verified', 'second event was account.verified')
assert.equal(mockLog.flowEvent.args[2][0].event, 'account.reminder', 'third event was account.reminder')
assert.equal(mockMailer.sendPostVerifyEmail.callCount, 1, 'sendPostVerifyEmail was called once')
assert.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
assert.equal(JSON.stringify(response), '{}')
})
.then(function () {
mockDB.verifyTokens.reset()
mockDB.verifyEmail.reset()
mockLog.activityEvent.reset()
mockLog.flowEvent.reset()
mockLog.notifyAttachedServices.reset()
mockMailer.sendPostVerifyEmail.reset()
mockPush.notifyUpdate.reset()
})
})
})
describe('verifyTokens resolves', function () {
before(() => {
dbData.emailVerified = true
dbErrors.verifyTokens = undefined
})
it('email verification', function () {
return runTest(route, mockRequest, function (response) {
assert.equal(mockDB.verifyTokens.callCount, 1, 'call db.verifyTokens')
assert.equal(mockDB.verifyEmail.callCount, 0, 'does not call db.verifyEmail')
assert.equal(mockLog.notifyAttachedServices.callCount, 0, 'does not call log.notifyAttachedServices')
assert.equal(mockLog.activityEvent.callCount, 0, 'log.activityEvent was not called')
assert.equal(mockPush.notifyUpdate.callCount, 0, 'mockPush.notifyUpdate should not have been called')
})
.then(function () {
mockDB.verifyTokens.reset()
})
})
it('sign-in confirmation', function () {
dbData.emailCode = crypto.randomBytes(16)
return runTest(route, mockRequest, function (response) {
assert.equal(mockDB.verifyTokens.callCount, 1, 'call db.verifyTokens')
assert.equal(mockDB.verifyEmail.callCount, 0, 'does not call db.verifyEmail')
assert.equal(mockLog.notifyAttachedServices.callCount, 0, 'does not call log.notifyAttachedServices')
assert.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
var args = mockLog.activityEvent.args[0]
assert.equal(args.length, 1, 'log.activityEvent was passed one argument')
assert.deepEqual(args[0], {
event: 'account.confirmed',
service: 'sync',
userAgent: 'test user-agent',
uid: uid.toString('hex')
}, 'event data was correct')
assert.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
args = mockPush.notifyUpdate.args[0]
assert.equal(args.length, 2, 'mockPush.notifyUpdate should have been passed two arguments')
assert.equal(args[0].toString('hex'), uid, 'first argument should have been uid')
assert.equal(args[1], 'accountConfirm', 'second argument should have been reason')
})
.then(function () {
mockDB.verifyTokens.reset()
mockLog.activityEvent.reset()
mockPush.notifyUpdate.reset()
})
})
})
})
describe('/account/keys', function () {
var keyFetchTokenId = crypto.randomBytes(16)
var uid = uuid.v4('binary')
@ -1906,177 +1189,3 @@ describe('/account/destroy', function () {
})
})
})
describe('/account/devices', function () {
it('should return the devices list', () => {
var mockRequest = mocks.mockRequest({
credentials: {
uid: crypto.randomBytes(16),
tokenId: crypto.randomBytes(16)
},
payload: {}
})
var unnamedDevice = { sessionToken: crypto.randomBytes(16) }
var mockDB = mocks.mockDB({
devices: [
{ name: 'current session', type: 'mobile', sessionToken: mockRequest.auth.credentials.tokenId },
{ name: 'has no type', sessionToken: crypto.randomBytes(16) },
{ name: 'has device type', sessionToken: crypto.randomBytes(16), uaDeviceType: 'wibble' },
unnamedDevice
]
})
var mockDevices = mocks.mockDevices()
var accountRoutes = makeRoutes({
db: mockDB,
devices: mockDevices
})
var route = getRoute(accountRoutes, '/account/devices')
return runTest(route, mockRequest, function (response) {
assert.ok(Array.isArray(response), 'response is array')
assert.equal(response.length, 4, 'response contains 4 items')
assert.equal(response[0].name, 'current session')
assert.equal(response[0].type, 'mobile')
assert.equal(response[0].sessionToken, undefined)
assert.equal(response[0].isCurrentDevice, true)
assert.equal(response[1].name, 'has no type')
assert.equal(response[1].type, 'desktop')
assert.equal(response[1].sessionToken, undefined)
assert.equal(response[1].isCurrentDevice, false)
assert.equal(response[2].name, 'has device type')
assert.equal(response[2].type, 'wibble')
assert.equal(response[2].isCurrentDevice, false)
assert.equal(response[3].name, null)
assert.equal(mockDB.devices.callCount, 1, 'db.devices was called once')
assert.equal(mockDB.devices.args[0].length, 1, 'db.devices was passed one argument')
assert.deepEqual(mockDB.devices.args[0][0], mockRequest.auth.credentials.uid, 'db.devices was passed uid')
assert.equal(mockDevices.synthesizeName.callCount, 1, 'mockDevices.synthesizeName was called once')
assert.equal(mockDevices.synthesizeName.args[0].length, 1, 'mockDevices.synthesizeName was passed one argument')
assert.equal(mockDevices.synthesizeName.args[0][0], unnamedDevice, 'mockDevices.synthesizeName was passed unnamed device')
})
})
})
describe('/account/login/send_unblock_code', function () {
var uid = uuid.v4('binary').toString('hex')
var email = 'unblock@example.com'
const mockLog = mocks.spyLog()
var mockRequest = mocks.mockRequest({
log: mockLog,
payload: {
email: email,
metricsContext: {
flowBeginTime: Date.now(),
flowId: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103'
}
}
})
var mockMailer = mocks.mockMailer()
var mockDb = mocks.mockDB({
uid: uid,
email: email
})
var config = {
signinUnblock: {
allowedEmailAddresses: /unblock.*$/
}
}
var accountRoutes = makeRoutes({
config: config,
db: mockDb,
log: mockLog,
mailer: mockMailer
})
var route = getRoute(accountRoutes, '/account/login/send_unblock_code')
afterEach(function () {
mockDb.emailRecord.reset()
mockDb.createUnblockCode.reset()
mockMailer.sendUnblockCode.reset()
})
it('signin unblock enabled', function () {
config.signinUnblock.enabled = true
return runTest(route, mockRequest, function (response) {
assert.ok(!(response instanceof Error), response.stack)
assert.deepEqual(response, {}, 'response has no keys')
assert.equal(mockDb.emailRecord.callCount, 1, 'db.emailRecord called')
assert.equal(mockDb.emailRecord.args[0][0], email)
assert.equal(mockDb.createUnblockCode.callCount, 1, 'db.createUnblockCode called')
var dbArgs = mockDb.createUnblockCode.args[0]
assert.equal(dbArgs.length, 1)
assert.equal(dbArgs[0], uid)
assert.equal(mockMailer.sendUnblockCode.callCount, 1, 'called mailer.sendUnblockCode')
var args = mockMailer.sendUnblockCode.args[0]
assert.equal(args.length, 3, 'mailer.sendUnblockCode called with 3 args')
assert.equal(mockLog.flowEvent.callCount, 1, 'log.flowEvent was called once')
assert.equal(mockLog.flowEvent.args[0][0].event, 'account.login.sentUnblockCode', 'event was account.login.sentUnblockCode')
mockLog.flowEvent.reset()
})
})
it('signin unblock disabled', function () {
config.signinUnblock.enabled = false
return runTest(route, mockRequest).then(() => assert.ok(false), err => {
assert.equal(err.output.statusCode, 503, 'correct status code is returned')
assert.equal(err.errno, error.ERRNO.FEATURE_NOT_ENABLED, 'correct errno is returned')
assert.equal(mockLog.flowEvent.callCount, 0, 'log.flowEvent was not called')
})
})
it('uses normalized email address for feature flag', function () {
config.signinUnblock.enabled = true
mockRequest.payload.email = 'UNBLOCK@example.com'
return runTest(route, mockRequest, function(response) {
assert.ok(!(response instanceof Error), response.stack)
assert.deepEqual(response, {}, 'response has no keys')
assert.equal(mockDb.emailRecord.callCount, 1, 'db.emailRecord called')
assert.equal(mockDb.emailRecord.args[0][0], mockRequest.payload.email)
assert.equal(mockDb.createUnblockCode.callCount, 1, 'db.createUnblockCode called')
assert.equal(mockMailer.sendUnblockCode.callCount, 1, 'called mailer.sendUnblockCode')
})
})
})
describe('/account/login/reject_unblock_code', function () {
it('should consume the unblock code', () => {
var uid = uuid.v4('binary').toString('hex')
var unblockCode = 'A1B2C3D4'
var mockRequest = mocks.mockRequest({
payload: {
uid: uid,
unblockCode: unblockCode
}
})
var mockDb = mocks.mockDB()
var accountRoutes = makeRoutes({
db: mockDb
})
var route = getRoute(accountRoutes, '/account/login/reject_unblock_code')
return runTest(route, mockRequest, function (response) {
assert.ok(!(response instanceof Error), response.stack)
assert.deepEqual(response, {}, 'response has no keys')
assert.equal(mockDb.consumeUnblockCode.callCount, 1, 'consumeUnblockCode is called')
var args = mockDb.consumeUnblockCode.args[0]
assert.equal(args.length, 2)
assert.equal(args[0].toString('hex'), uid)
assert.equal(args[1], unblockCode)
})
})
})

Просмотреть файл

@ -0,0 +1,449 @@
/* 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/. */
'use strict'
var sinon = require('sinon')
const assert = require('insist')
var mocks = require('../../mocks')
var getRoute = require('../../routes_helpers').getRoute
var proxyquire = require('proxyquire')
var P = require('../../../lib/promise')
var uuid = require('uuid')
var crypto = require('crypto')
var isA = require('joi')
var error = require('../../../lib/error')
var makeRoutes = function (options, requireMocks) {
options = 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
}
config.i18n = {
supportedLanguages: ['en'],
defaultLanguage: 'en'
}
config.lastAccessTimeUpdates = {}
config.signinConfirmation = config.signinConfirmation || {}
config.signinUnblock = config.signinUnblock || {}
var log = options.log || mocks.mockLog()
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) }
}
var checkPassword = options.checkPassword || require('../../../lib/routes/utils/password_check')(log, config, Password, customs, db)
var push = options.push || require('../../../lib/push')(log, db, {})
return proxyquire('../../../lib/routes/account', requireMocks || {})(
log,
require('../../../lib/crypto/random'),
P,
uuid,
isA,
error,
db,
options.mailer || {},
Password,
config,
customs,
isPreVerified,
checkPassword,
push,
options.devices || require('../../../lib/devices')(log, db, push)
)
}
function runTest (route, request, assertions) {
return new P(function (resolve, reject) {
route.handler(request, function (response) {
//resolve(response)
if (response instanceof Error) {
reject(response)
} else {
resolve(response)
}
})
})
.then(assertions)
}
describe('/account/device', function () {
var config = {}
var uid = uuid.v4('binary')
var deviceId = crypto.randomBytes(16)
var mockRequest = mocks.mockRequest({
credentials: {
deviceCallbackPublicKey: '',
deviceCallbackURL: '',
deviceId: deviceId,
deviceName: 'my awesome device',
deviceType: 'desktop',
tokenId: crypto.randomBytes(16),
uid: uid
},
payload: {
id: deviceId.toString('hex'),
name: 'my awesome device'
}
})
var mockDevices = mocks.mockDevices()
var mockLog = mocks.spyLog()
var accountRoutes = makeRoutes({
config: config,
devices: mockDevices,
log: mockLog
})
var route = getRoute(accountRoutes, '/account/device')
it('identical data', function () {
return runTest(route, mockRequest, function (response) {
assert.equal(mockLog.increment.callCount, 1, 'a counter was incremented')
assert.equal(mockLog.increment.firstCall.args[0], 'device.update.spurious')
assert.deepEqual(response, mockRequest.payload)
})
.then(function () {
mockLog.increment.reset()
})
})
it('different data', function () {
mockRequest.auth.credentials.deviceId = crypto.randomBytes(16)
var payload = mockRequest.payload
payload.name = 'my even awesomer device'
payload.type = 'phone'
payload.pushCallback = 'https://push.services.mozilla.com/123456'
payload.pushPublicKey = 'SomeEncodedBinaryStuffThatDoesntGetValidedByThisTest'
return runTest(route, mockRequest, function (response) {
assert.equal(mockLog.increment.callCount, 5, 'the counters were incremented')
assert.equal(mockLog.increment.getCall(0).args[0], 'device.update.sessionToken')
assert.equal(mockLog.increment.getCall(1).args[0], 'device.update.name')
assert.equal(mockLog.increment.getCall(2).args[0], 'device.update.type')
assert.equal(mockLog.increment.getCall(3).args[0], 'device.update.pushCallback')
assert.equal(mockLog.increment.getCall(4).args[0], 'device.update.pushPublicKey')
assert.equal(mockDevices.upsert.callCount, 1, 'devices.upsert was called once')
var args = mockDevices.upsert.args[0]
assert.equal(args.length, 3, 'devices.upsert was passed three arguments')
assert.equal(args[0], mockRequest, 'first argument was request object')
assert.deepEqual(args[1].tokenId, mockRequest.auth.credentials.tokenId, 'second argument was session token')
assert.deepEqual(args[1].uid, uid, 'sessionToken.uid was correct')
assert.deepEqual(args[2], mockRequest.payload, 'third argument was payload')
})
.then(function () {
mockLog.increment.reset()
mockDevices.upsert.reset()
})
})
it('with no id in payload', function () {
mockRequest.payload.id = undefined
return runTest(route, mockRequest, function (response) {
assert.equal(mockLog.increment.callCount, 0, 'log.increment was not called')
assert.equal(mockDevices.upsert.callCount, 1, 'devices.upsert was called once')
var args = mockDevices.upsert.args[0]
assert.equal(args[2].id, mockRequest.auth.credentials.deviceId.toString('hex'), 'payload.id defaulted to credentials.deviceId')
})
.then(function () {
mockLog.increment.reset()
mockDevices.upsert.reset()
})
})
it('device updates disabled', function () {
config.deviceUpdatesEnabled = false
return runTest(route, mockRequest, function () {
assert(false, 'should have thrown')
})
.then(() => assert.ok(false), function (err) {
assert.equal(err.output.statusCode, 503, 'correct status code is returned')
assert.equal(err.errno, error.ERRNO.FEATURE_NOT_ENABLED, 'correct errno is returned')
})
})
})
describe('/account/devices/notify', function () {
var config = {}
var uid = uuid.v4('binary')
var mockRequest = mocks.mockRequest({
credentials: {
uid: uid.toString('hex')
}
})
var pushPayload = {
isValid: true,
version: 1,
command: 'sync:collection_changed',
data: {
collections: ['clients']
}
}
var mockPush = mocks.mockPush()
var validate = sinon.spy(function (payload) { return payload.isValid })
var mockAjv = function () {
return {
compile: function () {
return validate
}
}
}
var sandbox = sinon.sandbox.create()
var mockCustoms = mocks.mockCustoms()
var accountRoutes = makeRoutes({
config: config,
customs: mockCustoms,
push: mockPush
}, {
ajv: mockAjv
})
var route = getRoute(accountRoutes, '/account/devices/notify')
it('bad payload', function () {
mockRequest.payload = {
to: ['bogusid1'],
payload: {
isValid: false
}
}
return runTest(route, mockRequest, function () {
assert(false, 'should have thrown')
})
.then(() => assert(false), function (err) {
assert.equal(validate.callCount, 1, 'ajv validator function was called')
assert.equal(mockPush.pushToDevices.callCount, 0, 'mockPush.pushToDevices was not called')
assert.equal(err.errno, 107, 'Correct errno for invalid push payload')
})
})
it('all devices', function () {
mockRequest.payload = {
to: 'all',
excluded: ['bogusid'],
TTL: 60,
payload: pushPayload
}
return runTest(route, mockRequest, function (response) {
assert.equal(mockCustoms.checkAuthenticated.callCount, 1, 'mockCustoms.checkAuthenticated was called once')
assert.equal(mockPush.pushToAllDevices.callCount, 1, 'mockPush.pushToAllDevices was called once')
var args = mockPush.pushToAllDevices.args[0]
assert.equal(args.length, 3, 'mockPush.pushToAllDevices was passed three arguments')
assert.equal(args[0], uid.toString('hex'), 'first argument was the device uid')
assert.equal(args[1], 'devicesNotify', 'second argument was the devicesNotify reason')
assert.deepEqual(args[2], {
data: new Buffer(JSON.stringify(pushPayload)),
excludedDeviceIds: ['bogusid'],
TTL: 60
}, 'third argument was the push options')
})
})
it('specific devices', function () {
mockCustoms.checkAuthenticated.reset()
mockRequest.payload = {
to: ['bogusid1', 'bogusid2'],
TTL: 60,
payload: pushPayload
}
return runTest(route, mockRequest, function (response) {
assert.equal(mockCustoms.checkAuthenticated.callCount, 1, 'mockCustoms.checkAuthenticated was called once')
assert.equal(mockPush.pushToDevices.callCount, 1, 'mockPush.pushToDevices was called once')
var args = mockPush.pushToDevices.args[0]
assert.equal(args.length, 4, 'mockPush.pushToDevices was passed four arguments')
assert.equal(args[0], uid.toString('hex'), 'first argument was the device uid')
assert.deepEqual(args[1], ['bogusid1', 'bogusid2'], 'second argument was the list of device ids')
assert.equal(args[2], 'devicesNotify', 'third argument was the devicesNotify reason')
assert.deepEqual(args[3], {
data: new Buffer(JSON.stringify(pushPayload)),
TTL: 60
}, 'fourth argument was the push options')
})
})
it('device driven notifications disabled', function () {
config.deviceNotificationsEnabled = false
mockRequest.payload = {
to: 'all',
excluded: ['bogusid'],
TTL: 60,
payload: pushPayload
}
return runTest(route, mockRequest, function () {
assert(false, 'should have thrown')
})
.then(() => assert.ok(false), function (err) {
assert.equal(err.output.statusCode, 503, 'correct status code is returned')
assert.equal(err.errno, error.ERRNO.FEATURE_NOT_ENABLED, 'correct errno is returned')
})
})
it('throws error if customs blocked the request', function () {
config.deviceNotificationsEnabled = true
mockCustoms = mocks.mockCustoms({
checkAuthenticated: sandbox.spy(function () {
throw error.tooManyRequests(1)
})
})
route = getRoute(makeRoutes({customs: mockCustoms}), '/account/devices/notify')
return runTest(route, mockRequest, function (response) {
assert(false, 'should have thrown')
})
.then(() => assert(false), function (err) {
assert.equal(mockCustoms.checkAuthenticated.callCount, 1, 'mockCustoms.checkAuthenticated was called once')
assert.equal(err.message, 'Client has sent too many requests')
})
})
it('logs error if no devices found', () => {
mockRequest.payload = {
to: ['bogusid1', 'bogusid2'],
TTL: 60,
payload: pushPayload
}
var mockLog = mocks.spyLog()
var mockPush = mocks.mockPush({
pushToDevices: () => P.reject('Devices ids not found in devices')
})
var mockCustoms = {
checkAuthenticated: () => P.resolve()
}
route = getRoute(makeRoutes({
customs: mockCustoms,
log: mockLog,
push: mockPush
}), '/account/devices/notify')
return runTest(route, mockRequest, function (response) {
assert.equal(JSON.stringify(response), '{}', 'response should not throw push errors')
})
})
})
describe('/account/device/destroy', function () {
it('should work', () => {
var uid = uuid.v4('binary')
var deviceId = crypto.randomBytes(16).toString('hex')
var mockLog = mocks.spyLog()
var mockDB = mocks.mockDB()
var mockRequest = mocks.mockRequest({
credentials: {
uid: uid.toString('hex'),
},
log: mockLog,
payload: {
id: deviceId
}
})
var mockPush = mocks.mockPush()
var accountRoutes = makeRoutes({
db: mockDB,
log: mockLog,
push: mockPush
})
var route = getRoute(accountRoutes, '/account/device/destroy')
return runTest(route, mockRequest, function () {
assert.equal(mockDB.deleteDevice.callCount, 1)
assert.equal(mockPush.notifyDeviceDisconnected.callCount, 1)
assert.equal(mockPush.notifyDeviceDisconnected.firstCall.args[0], mockRequest.auth.credentials.uid)
assert.equal(mockPush.notifyDeviceDisconnected.firstCall.args[1], deviceId)
assert.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
var args = mockLog.activityEvent.args[0]
assert.equal(args.length, 1, 'log.activityEvent was passed one argument')
assert.deepEqual(args[0], {
event: 'device.deleted',
service: undefined,
userAgent: 'test user-agent',
uid: uid.toString('hex'),
device_id: deviceId
}, 'event data was correct')
assert.equal(mockLog.notifyAttachedServices.callCount, 1)
args = mockLog.notifyAttachedServices.args[0]
assert.equal(args.length, 3)
assert.equal(args[0], 'device:delete')
assert.equal(args[1], mockRequest)
var details = args[2]
assert.equal(details.uid, uid.toString('hex'))
assert.equal(details.id, deviceId)
assert.ok(Date.now() - details.timestamp < 100)
})
})
})
describe('/account/devices', function () {
it('should return the devices list', () => {
var mockRequest = mocks.mockRequest({
credentials: {
uid: crypto.randomBytes(16),
tokenId: crypto.randomBytes(16)
},
payload: {}
})
var unnamedDevice = { sessionToken: crypto.randomBytes(16) }
var mockDB = mocks.mockDB({
devices: [
{ name: 'current session', type: 'mobile', sessionToken: mockRequest.auth.credentials.tokenId },
{ name: 'has no type', sessionToken: crypto.randomBytes(16) },
{ name: 'has device type', sessionToken: crypto.randomBytes(16), uaDeviceType: 'wibble' },
unnamedDevice
]
})
var mockDevices = mocks.mockDevices()
var accountRoutes = makeRoutes({
db: mockDB,
devices: mockDevices
})
var route = getRoute(accountRoutes, '/account/devices')
return runTest(route, mockRequest, function (response) {
assert.ok(Array.isArray(response), 'response is array')
assert.equal(response.length, 4, 'response contains 4 items')
assert.equal(response[0].name, 'current session')
assert.equal(response[0].type, 'mobile')
assert.equal(response[0].sessionToken, undefined)
assert.equal(response[0].isCurrentDevice, true)
assert.equal(response[1].name, 'has no type')
assert.equal(response[1].type, 'desktop')
assert.equal(response[1].sessionToken, undefined)
assert.equal(response[1].isCurrentDevice, false)
assert.equal(response[2].name, 'has device type')
assert.equal(response[2].type, 'wibble')
assert.equal(response[2].isCurrentDevice, false)
assert.equal(response[3].name, null)
assert.equal(mockDB.devices.callCount, 1, 'db.devices was called once')
assert.equal(mockDB.devices.args[0].length, 1, 'db.devices was passed one argument')
assert.deepEqual(mockDB.devices.args[0][0], mockRequest.auth.credentials.uid, 'db.devices was passed uid')
assert.equal(mockDevices.synthesizeName.callCount, 1, 'mockDevices.synthesizeName was called once')
assert.equal(mockDevices.synthesizeName.args[0].length, 1, 'mockDevices.synthesizeName was passed one argument')
assert.equal(mockDevices.synthesizeName.args[0][0], unnamedDevice, 'mockDevices.synthesizeName was passed unnamed device')
})
})
})

Просмотреть файл

@ -0,0 +1,194 @@
/* 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/. */
'use strict'
const assert = require('insist')
var mocks = require('../../mocks')
var getRoute = require('../../routes_helpers').getRoute
var proxyquire = require('proxyquire')
var P = require('../../../lib/promise')
var uuid = require('uuid')
var isA = require('joi')
var error = require('../../../lib/error')
var makeRoutes = function (options, requireMocks) {
options = 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
}
config.i18n = {
supportedLanguages: ['en'],
defaultLanguage: 'en'
}
config.lastAccessTimeUpdates = {}
config.signinConfirmation = config.signinConfirmation || {}
config.signinUnblock = config.signinUnblock || {}
var log = options.log || mocks.mockLog()
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) }
}
var checkPassword = options.checkPassword || require('../../../lib/routes/utils/password_check')(log, config, Password, customs, db)
var push = options.push || require('../../../lib/push')(log, db, {})
return proxyquire('../../../lib/routes/account', requireMocks || {})(
log,
require('../../../lib/crypto/random'),
P,
uuid,
isA,
error,
db,
options.mailer || {},
Password,
config,
customs,
isPreVerified,
checkPassword,
push,
options.devices || require('../../../lib/devices')(log, db, push)
)
}
function runTest (route, request, assertions) {
return new P(function (resolve, reject) {
route.handler(request, function (response) {
//resolve(response)
if (response instanceof Error) {
reject(response)
} else {
resolve(response)
}
})
})
.then(assertions)
}
describe('/account/login/send_unblock_code', function () {
var uid = uuid.v4('binary').toString('hex')
var email = 'unblock@example.com'
const mockLog = mocks.spyLog()
var mockRequest = mocks.mockRequest({
log: mockLog,
payload: {
email: email,
metricsContext: {
flowBeginTime: Date.now(),
flowId: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103'
}
}
})
var mockMailer = mocks.mockMailer()
var mockDb = mocks.mockDB({
uid: uid,
email: email
})
var config = {
signinUnblock: {
allowedEmailAddresses: /unblock.*$/
}
}
var accountRoutes = makeRoutes({
config: config,
db: mockDb,
log: mockLog,
mailer: mockMailer
})
var route = getRoute(accountRoutes, '/account/login/send_unblock_code')
afterEach(function () {
mockDb.emailRecord.reset()
mockDb.createUnblockCode.reset()
mockMailer.sendUnblockCode.reset()
})
it('signin unblock enabled', function () {
config.signinUnblock.enabled = true
return runTest(route, mockRequest, function (response) {
assert.ok(!(response instanceof Error), response.stack)
assert.deepEqual(response, {}, 'response has no keys')
assert.equal(mockDb.emailRecord.callCount, 1, 'db.emailRecord called')
assert.equal(mockDb.emailRecord.args[0][0], email)
assert.equal(mockDb.createUnblockCode.callCount, 1, 'db.createUnblockCode called')
var dbArgs = mockDb.createUnblockCode.args[0]
assert.equal(dbArgs.length, 1)
assert.equal(dbArgs[0], uid)
assert.equal(mockMailer.sendUnblockCode.callCount, 1, 'called mailer.sendUnblockCode')
var args = mockMailer.sendUnblockCode.args[0]
assert.equal(args.length, 3, 'mailer.sendUnblockCode called with 3 args')
assert.equal(mockLog.flowEvent.callCount, 1, 'log.flowEvent was called once')
assert.equal(mockLog.flowEvent.args[0][0].event, 'account.login.sentUnblockCode', 'event was account.login.sentUnblockCode')
mockLog.flowEvent.reset()
})
})
it('signin unblock disabled', function () {
config.signinUnblock.enabled = false
return runTest(route, mockRequest).then(() => assert.ok(false), err => {
assert.equal(err.output.statusCode, 503, 'correct status code is returned')
assert.equal(err.errno, error.ERRNO.FEATURE_NOT_ENABLED, 'correct errno is returned')
assert.equal(mockLog.flowEvent.callCount, 0, 'log.flowEvent was not called')
})
})
it('uses normalized email address for feature flag', function () {
config.signinUnblock.enabled = true
mockRequest.payload.email = 'UNBLOCK@example.com'
return runTest(route, mockRequest, function(response) {
assert.ok(!(response instanceof Error), response.stack)
assert.deepEqual(response, {}, 'response has no keys')
assert.equal(mockDb.emailRecord.callCount, 1, 'db.emailRecord called')
assert.equal(mockDb.emailRecord.args[0][0], mockRequest.payload.email)
assert.equal(mockDb.createUnblockCode.callCount, 1, 'db.createUnblockCode called')
assert.equal(mockMailer.sendUnblockCode.callCount, 1, 'called mailer.sendUnblockCode')
})
})
})
describe('/account/login/reject_unblock_code', function () {
it('should consume the unblock code', () => {
var uid = uuid.v4('binary').toString('hex')
var unblockCode = 'A1B2C3D4'
var mockRequest = mocks.mockRequest({
payload: {
uid: uid,
unblockCode: unblockCode
}
})
var mockDb = mocks.mockDB()
var accountRoutes = makeRoutes({
db: mockDb
})
var route = getRoute(accountRoutes, '/account/login/reject_unblock_code')
return runTest(route, mockRequest, function (response) {
assert.ok(!(response instanceof Error), response.stack)
assert.deepEqual(response, {}, 'response has no keys')
assert.equal(mockDb.consumeUnblockCode.callCount, 1, 'consumeUnblockCode is called')
var args = mockDb.consumeUnblockCode.args[0]
assert.equal(args.length, 2)
assert.equal(args[0].toString('hex'), uid)
assert.equal(args[1], unblockCode)
})
})
})

Просмотреть файл

@ -5,16 +5,16 @@
'use strict'
const assert = require('insist')
var mocks = require('../mocks')
var getRoute = require('../routes_helpers').getRoute
var mocks = require('../../mocks')
var getRoute = require('../../routes_helpers').getRoute
var P = require('../../lib/promise')
var P = require('../../../lib/promise')
var uuid = require('uuid')
var crypto = require('crypto')
var isA = require('joi')
var error = require('../../lib/error')
var error = require('../../../lib/error')
const sinon = require('sinon')
const log = require('../../lib/log')
const log = require('../../../lib/log')
var TEST_EMAIL = 'foo@gmail.com'
@ -27,10 +27,10 @@ function makeRoutes(options) {
}
var log = options.log || mocks.mockLog()
var db = options.db || {}
var Password = require('../../lib/crypto/password')(log, config)
var Password = require('../../../lib/crypto/password')(log, config)
var customs = options.customs || {}
var checkPassword = require('../../lib/routes/utils/password_check')(log, config, Password, customs, db)
return require('../../lib/routes/password')(
var checkPassword = require('../../../lib/routes/utils/password_check')(log, config, Password, customs, db)
return require('../../../lib/routes/password')(
log,
isA,
error,

Просмотреть файл

@ -0,0 +1,484 @@
/* 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/. */
'use strict'
var sinon = require('sinon')
const assert = require('insist')
var mocks = require('../../mocks')
var getRoute = require('../../routes_helpers').getRoute
var proxyquire = require('proxyquire')
var P = require('../../../lib/promise')
var uuid = require('uuid')
var crypto = require('crypto')
var isA = require('joi')
var error = require('../../../lib/error')
var TEST_EMAIL = 'foo@gmail.com'
var TEST_EMAIL_INVALID = 'example@dotless-domain'
var makeRoutes = function (options, requireMocks) {
options = 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
}
config.i18n = {
supportedLanguages: ['en'],
defaultLanguage: 'en'
}
config.lastAccessTimeUpdates = {}
config.signinConfirmation = config.signinConfirmation || {}
config.signinUnblock = config.signinUnblock || {}
var log = options.log || mocks.mockLog()
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) }
}
var checkPassword = options.checkPassword || require('../../../lib/routes/utils/password_check')(log, config, Password, customs, db)
var push = options.push || require('../../../lib/push')(log, db, {})
return proxyquire('../../../lib/routes/account', requireMocks || {})(
log,
require('../../../lib/crypto/random'),
P,
uuid,
isA,
error,
db,
options.mailer || {},
Password,
config,
customs,
isPreVerified,
checkPassword,
push,
options.devices || require('../../../lib/devices')(log, db, push)
)
}
function runTest (route, request, assertions) {
return new P(function (resolve, reject) {
route.handler(request, function (response) {
//resolve(response)
if (response instanceof Error) {
reject(response)
} else {
resolve(response)
}
})
})
.then(assertions)
}
describe('/recovery_email/status', function () {
var config = {}
var mockDB = mocks.mockDB()
var pushCalled
var mockLog = mocks.mockLog({
increment: function (name) {
if (name === 'recovery_email_reason.push') {
pushCalled = true
}
}
})
var accountRoutes = makeRoutes({
config: config,
db: mockDB,
log: mockLog
})
var route = getRoute(accountRoutes, '/recovery_email/status')
var mockRequest = mocks.mockRequest({
credentials: {
uid: uuid.v4('binary').toString('hex'),
email: TEST_EMAIL
}
})
describe('invalid email', function () {
var mockRequest = mocks.mockRequest({
credentials: {
email: TEST_EMAIL_INVALID
}
})
it('unverified account', function () {
mockRequest.auth.credentials.emailVerified = false
return runTest(route, mockRequest).then(() => assert.ok(false), function (response) {
assert.equal(mockDB.deleteAccount.callCount, 1)
assert.equal(mockDB.deleteAccount.firstCall.args[0].email, TEST_EMAIL_INVALID)
assert.equal(response.errno, error.ERRNO.INVALID_TOKEN)
})
.then(function () {
mockDB.deleteAccount.reset()
})
})
it('verified account', function () {
mockRequest.auth.credentials.uid = uuid.v4('binary').toString('hex')
mockRequest.auth.credentials.emailVerified = true
mockRequest.auth.credentials.tokenVerified = true
return runTest(route, mockRequest, function (response) {
assert.equal(mockDB.deleteAccount.callCount, 0)
assert.deepEqual(response, {
email: TEST_EMAIL_INVALID,
verified: true,
emailVerified: true,
sessionVerified: true
})
})
})
})
it('valid email, verified account', function () {
pushCalled = false
var mockRequest = mocks.mockRequest({
credentials: {
uid: uuid.v4('binary').toString('hex'),
email: TEST_EMAIL,
emailVerified: true,
tokenVerified: true
},
query: {
reason: 'push'
}
})
return runTest(route, mockRequest, function (response) {
assert.equal(pushCalled, true)
assert.deepEqual(response, {
email: TEST_EMAIL,
verified: true,
emailVerified: true,
sessionVerified: true
})
})
})
it('verified account, verified session', function () {
mockRequest.auth.credentials.emailVerified = true
mockRequest.auth.credentials.tokenVerified = true
return runTest(route, mockRequest, function (response) {
assert.deepEqual(response, {
email: TEST_EMAIL,
verified: true,
sessionVerified: true,
emailVerified: true
})
})
})
it('verified account, unverified session, must verify session', function () {
mockRequest.auth.credentials.emailVerified = true
mockRequest.auth.credentials.tokenVerified = false
mockRequest.auth.credentials.mustVerify = true
return runTest(route, mockRequest, function (response) {
assert.deepEqual(response, {
email: TEST_EMAIL,
verified: false,
sessionVerified: false,
emailVerified: true
})
})
})
it('verified account, unverified session, neednt verify session', function () {
mockRequest.auth.credentials.emailVerified = true
mockRequest.auth.credentials.tokenVerified = false
mockRequest.auth.credentials.mustVerify = false
return runTest(route, mockRequest, function (response) {
assert.deepEqual(response, {
email: TEST_EMAIL,
verified: true,
sessionVerified: false,
emailVerified: true
})
})
})
})
describe('/recovery_email/resend_code', () => {
const config = {}
const mockDB = mocks.mockDB()
const mockLog = mocks.mockLog()
mockLog.flowEvent = sinon.spy(() => {
return P.resolve()
})
const mockMailer = mocks.mockMailer()
const mockMetricsContext = mocks.mockMetricsContext()
const accountRoutes = makeRoutes({
config: config,
db: mockDB,
log: mockLog,
mailer: mockMailer
})
const route = getRoute(accountRoutes, '/recovery_email/resend_code')
it('verification', () => {
const mockRequest = mocks.mockRequest({
log: mockLog,
metricsContext: mockMetricsContext,
credentials: {
uid: uuid.v4('binary').toString('hex'),
email: TEST_EMAIL,
emailVerified: false,
tokenVerified: false,
uaBrowser: 'Firefox',
uaBrowserVersion: 52,
uaOS: 'Mac OS X',
uaOSVersion: '10.10'
},
query: {},
payload: {
metricsContext: {
flowBeginTime: Date.now(),
flowId: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103'
}
}
})
mockLog.flowEvent.reset()
return runTest(route, mockRequest, response => {
assert.equal(mockLog.flowEvent.callCount, 1, 'log.flowEvent called once')
assert.equal(mockLog.flowEvent.args[0][0].event, 'email.verification.resent')
assert.equal(mockMailer.sendVerifyCode.callCount, 1)
const args = mockMailer.sendVerifyCode.args[0]
assert.equal(args[2].uaBrowser, 'Firefox')
assert.equal(args[2].uaBrowserVersion, '52')
assert.equal(args[2].uaOS, 'Mac OS X')
assert.equal(args[2].uaOSVersion, '10.10')
assert.strictEqual(args[2].uaDeviceType, undefined)
})
})
it('confirmation', () => {
const mockRequest = mocks.mockRequest({
log: mockLog,
metricsContext: mockMetricsContext,
credentials: {
uid: uuid.v4('binary').toString('hex'),
email: TEST_EMAIL,
emailVerified: true,
tokenVerified: false,
uaBrowser: 'Firefox',
uaBrowserVersion: '50',
uaOS: 'Android',
uaOSVersion: '6',
uaDeviceType: 'tablet'
},
query: {},
payload: {
metricsContext: {
flowBeginTime: Date.now(),
flowId: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103'
}
}
})
mockLog.flowEvent.reset()
return runTest(route, mockRequest, response => {
assert.equal(mockLog.flowEvent.callCount, 1, 'log.flowEvent called once')
assert.equal(mockLog.flowEvent.args[0][0].event, 'email.confirmation.resent')
assert.equal(mockMailer.sendVerifyLoginEmail.callCount, 1)
const args = mockMailer.sendVerifyLoginEmail.args[0]
assert.equal(args[2].uaBrowser, 'Firefox')
assert.equal(args[2].uaBrowserVersion, '50')
assert.equal(args[2].uaOS, 'Android')
assert.equal(args[2].uaOSVersion, '6')
assert.strictEqual(args[2].uaDeviceType, 'tablet')
})
})
})
describe('/recovery_email/verify_code', function () {
var uid = uuid.v4('binary').toString('hex')
const mockLog = mocks.spyLog()
const mockRequest = mocks.mockRequest({
log: mockLog,
metricsContext: mocks.mockMetricsContext({
gather (data) {
return Promise.resolve(Object.assign(data, {
flowCompleteSignal: 'account.signed',
flow_time: 10000,
flow_id: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103',
time: Date.now() - 10000
}))
}
}),
query: {},
payload: {
uid: uid,
code: 'e3c5b0e3f5391e134596c27519979b93',
service: 'sync'
}
})
var dbData = {
email: TEST_EMAIL,
emailCode: Buffer(mockRequest.payload.code, 'hex'),
emailVerified: false,
uid: uid
}
var dbErrors = {
verifyTokens: error.invalidVerificationCode({})
}
var mockDB = mocks.mockDB(dbData, dbErrors)
var mockMailer = mocks.mockMailer()
const mockPush = mocks.mockPush()
var mockCustoms = mocks.mockCustoms()
var accountRoutes = makeRoutes({
checkPassword: function () {
return P.resolve(true)
},
config: {},
customs: mockCustoms,
db: mockDB,
log: mockLog,
mailer: mockMailer,
push: mockPush
})
var route = getRoute(accountRoutes, '/recovery_email/verify_code')
describe('verifyTokens rejects with INVALID_VERIFICATION_CODE', function () {
it('without a reminder payload', function () {
return runTest(route, mockRequest, function (response) {
assert.equal(mockDB.verifyTokens.callCount, 1, 'calls verifyTokens')
assert.equal(mockDB.verifyEmail.callCount, 1, 'calls verifyEmail')
assert.equal(mockCustoms.check.callCount, 1, 'calls customs.check')
assert.equal(mockLog.notifyAttachedServices.callCount, 1, 'logs verified')
assert.equal(mockMailer.sendPostVerifyEmail.callCount, 1, 'sendPostVerifyEmail was called once')
assert.equal(mockLog.activityEvent.callCount, 1, 'activityEvent was called once')
let args = mockLog.activityEvent.args[0]
assert.equal(args.length, 1, 'log.activityEvent was passed one argument')
assert.deepEqual(args[0], {
event: 'account.verified',
service: 'sync',
userAgent: 'test user-agent',
uid: uid.toString('hex')
}, 'event data was correct')
assert.equal(mockLog.flowEvent.callCount, 2, 'flowEvent was called twice')
assert.equal(mockLog.flowEvent.args[0][0].event, 'email.verify_code.clicked', 'first event was email.verify_code.clicked')
assert.equal(mockLog.flowEvent.args[1][0].event, 'account.verified', 'second event was event account.verified')
assert.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
args = mockPush.notifyUpdate.args[0]
assert.equal(args.length, 2, 'mockPush.notifyUpdate should have been passed two arguments')
assert.equal(args[0].toString('hex'), uid, 'first argument should have been uid')
assert.equal(args[1], 'accountVerify', 'second argument should have been reason')
assert.equal(JSON.stringify(response), '{}')
})
.then(function () {
mockDB.verifyTokens.reset()
mockDB.verifyEmail.reset()
mockLog.activityEvent.reset()
mockLog.flowEvent.reset()
mockLog.notifyAttachedServices.reset()
mockMailer.sendPostVerifyEmail.reset()
mockPush.notifyUpdate.reset()
})
})
it('with a reminder payload', function () {
mockRequest.payload.reminder = 'second'
return runTest(route, mockRequest, function (response) {
assert.equal(mockLog.activityEvent.callCount, 1, 'activityEvent was called once')
assert.equal(mockLog.flowEvent.callCount, 3, 'flowEvent was called thrice')
assert.equal(mockLog.flowEvent.args[0][0].event, 'email.verify_code.clicked', 'first event was email.verify_code.clicked')
assert.equal(mockLog.flowEvent.args[1][0].event, 'account.verified', 'second event was account.verified')
assert.equal(mockLog.flowEvent.args[2][0].event, 'account.reminder', 'third event was account.reminder')
assert.equal(mockMailer.sendPostVerifyEmail.callCount, 1, 'sendPostVerifyEmail was called once')
assert.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
assert.equal(JSON.stringify(response), '{}')
})
.then(function () {
mockDB.verifyTokens.reset()
mockDB.verifyEmail.reset()
mockLog.activityEvent.reset()
mockLog.flowEvent.reset()
mockLog.notifyAttachedServices.reset()
mockMailer.sendPostVerifyEmail.reset()
mockPush.notifyUpdate.reset()
})
})
})
describe('verifyTokens resolves', function () {
before(() => {
dbData.emailVerified = true
dbErrors.verifyTokens = undefined
})
it('email verification', function () {
return runTest(route, mockRequest, function (response) {
assert.equal(mockDB.verifyTokens.callCount, 1, 'call db.verifyTokens')
assert.equal(mockDB.verifyEmail.callCount, 0, 'does not call db.verifyEmail')
assert.equal(mockLog.notifyAttachedServices.callCount, 0, 'does not call log.notifyAttachedServices')
assert.equal(mockLog.activityEvent.callCount, 0, 'log.activityEvent was not called')
assert.equal(mockPush.notifyUpdate.callCount, 0, 'mockPush.notifyUpdate should not have been called')
})
.then(function () {
mockDB.verifyTokens.reset()
})
})
it('sign-in confirmation', function () {
dbData.emailCode = crypto.randomBytes(16)
return runTest(route, mockRequest, function (response) {
assert.equal(mockDB.verifyTokens.callCount, 1, 'call db.verifyTokens')
assert.equal(mockDB.verifyEmail.callCount, 0, 'does not call db.verifyEmail')
assert.equal(mockLog.notifyAttachedServices.callCount, 0, 'does not call log.notifyAttachedServices')
assert.equal(mockLog.activityEvent.callCount, 1, 'log.activityEvent was called once')
var args = mockLog.activityEvent.args[0]
assert.equal(args.length, 1, 'log.activityEvent was passed one argument')
assert.deepEqual(args[0], {
event: 'account.confirmed',
service: 'sync',
userAgent: 'test user-agent',
uid: uid.toString('hex')
}, 'event data was correct')
assert.equal(mockPush.notifyUpdate.callCount, 1, 'mockPush.notifyUpdate should have been called once')
args = mockPush.notifyUpdate.args[0]
assert.equal(args.length, 2, 'mockPush.notifyUpdate should have been passed two arguments')
assert.equal(args[0].toString('hex'), uid, 'first argument should have been uid')
assert.equal(args[1], 'accountConfirm', 'second argument should have been reason')
})
.then(function () {
mockDB.verifyTokens.reset()
mockLog.activityEvent.reset()
mockPush.notifyUpdate.reset()
})
})
})
})

Просмотреть файл

@ -5,7 +5,7 @@
'use strict'
const assert = require('insist')
const requestHelper = require('../../lib/routes/utils/request_helper')
const requestHelper = require('../../../lib/routes/utils/request_helper')
describe('requestHelper', () => {
it(

Просмотреть файл

@ -7,11 +7,11 @@
const assert = require('insist')
var crypto = require('crypto')
var uuid = require('uuid')
var error = require('../../lib/error')
var getRoute = require('../routes_helpers').getRoute
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 mocks = require('../../mocks')
var P = require('../../../lib/promise')
describe('/certificate/sign', () => {
var deviceId = crypto.randomBytes(16)
@ -142,7 +142,7 @@ describe('/certificate/sign', () => {
var log = options.log || mocks.mockLog()
return require('../../lib/routes/sign')(
return require('../../../lib/routes/sign')(
log,
P,
isA,

Просмотреть файл

@ -7,7 +7,7 @@
const assert = require('insist')
const log = { trace() {} }
const tokens = require('../../lib/tokens')(log)
const tokens = require('../../../lib/tokens/index')(log)
const AccountResetToken = tokens.AccountResetToken
const ACCOUNT = {

Просмотреть файл

@ -9,11 +9,11 @@ const log = { trace() {} }
const timestamp = Date.now()
const PasswordForgotToken = require('../../lib/tokens/password_forgot_token')(
const PasswordForgotToken = require('../../../lib/tokens/password_forgot_token')(
log,
require('util').inherits,
require('../../lib/tokens')(log),
require('../../lib/crypto/random'),
require('../../../lib/tokens/index')(log),
require('../../../lib/crypto/random'),
1000 * 60 * 15 // 15 minutes
)

Просмотреть файл

@ -8,7 +8,7 @@ const assert = require('insist')
const crypto = require('crypto')
const log = { trace() {} }
const tokens = require('../../lib/tokens')(log)
const tokens = require('../../../lib/tokens/index')(log)
const KeyFetchToken = tokens.KeyFetchToken
const ACCOUNT = {

Просмотреть файл

@ -12,10 +12,10 @@ var crypto = require('crypto')
const config = {
lastAccessTimeUpdates: {}
}
const tokens = require('../../lib/tokens')(log, config)
const tokens = require('../../../lib/tokens/index')(log, config)
var SessionToken = tokens.SessionToken
var TOKEN_FRESHNESS_THRESHOLD = require('../../lib/tokens/session_token').TOKEN_FRESHNESS_THREADHOLD
var TOKEN_FRESHNESS_THRESHOLD = require('../../../lib/tokens/session_token').TOKEN_FRESHNESS_THREADHOLD
var ACCOUNT = {
createdAt: Date.now(),

Просмотреть файл

@ -6,9 +6,9 @@
const assert = require('insist')
var crypto = require('crypto')
var hkdf = require('../../lib/crypto/hkdf')
var mocks = require('../mocks')
var P = require('../../lib/promise')
var hkdf = require('../../../lib/crypto/hkdf')
var mocks = require('../../mocks')
var P = require('../../../lib/promise')
var sinon = require('sinon')
var Bundle = {
@ -16,7 +16,7 @@ var Bundle = {
unbundle: sinon.spy()
}
var log = mocks.spyLog()
var modulePath = '../../lib/tokens/token'
var modulePath = '../../../lib/tokens/token'
describe('Token', () => {
@ -24,7 +24,7 @@ describe('Token', () => {
let Token
before(() => {
delete require.cache[require.resolve(modulePath)]
delete require.cache[require.resolve('../../config')]
delete require.cache[require.resolve('../../../config')]
process.env.NODE_ENV = 'dev'
Token = require(modulePath)(log, crypto, P, hkdf, Bundle, null)
})
@ -61,7 +61,7 @@ describe('Token', () => {
let Token
before(() => {
delete require.cache[require.resolve(modulePath)]
delete require.cache[require.resolve('../../config')]
delete require.cache[require.resolve('../../../config')]
process.env.NODE_ENV = 'prod'
Token = require(modulePath)(log, crypto, P, hkdf, Bundle, null)
})

Просмотреть файл