refactor(tests): Reorganize local tests (#1629) r=vladikoff,philbooth
This commit is contained in:
Родитель
2e84e07e02
Коммит
38d4957f28
|
@ -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)
|
||||
})
|
Загрузка…
Ссылка в новой задаче